blob: 58c509e6ac6a8fb2713ddc8994cbee0979541e26 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French75865f8c2007-06-24 18:30:48 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
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
Steve Frenchf1914012005-08-18 09:37:34 -070052static DECLARE_COMPLETION(cifsd_complete);
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
55 unsigned char *p24);
56
57extern mempool_t *cifs_req_poolp;
58
59struct smb_vol {
60 char *username;
61 char *password;
62 char *domainname;
63 char *UNC;
64 char *UNCip;
65 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
66 char *iocharset; /* local code page for mapping to and from Unicode */
67 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070068 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 uid_t linux_uid;
70 gid_t linux_gid;
71 mode_t file_mode;
72 mode_t dir_mode;
Steve French189acaa2006-06-23 02:33:48 +000073 unsigned secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 unsigned rw:1;
75 unsigned retry:1;
76 unsigned intr:1;
77 unsigned setuids:1;
Steve French4523cc32007-04-30 20:13:06 +000078 unsigned override_uid:1;
79 unsigned override_gid:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 unsigned noperm:1;
81 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
Steve French0a4b92c2006-01-12 15:44:21 -080082 unsigned cifs_acl:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
84 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
85 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070086 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Jeremy Allisonac670552005-06-22 17:26:35 -070087 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
Steve Frenchc18c8422007-07-18 23:21:09 +000088 unsigned no_linux_ext:1;
Steve Frenchd7245c22005-07-14 18:25:12 -050089 unsigned sfu_emul:1;
Steve Frenchbf820672005-12-01 22:32:42 -080090 unsigned nullauth:1; /* attempt to authenticate with null user */
Steve Frenchc46fa8a2005-08-18 20:49:57 -070091 unsigned nocase; /* request case insensitive filenames */
92 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 unsigned int rsize;
94 unsigned int wsize;
95 unsigned int sockopt;
96 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000097 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098};
99
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000100static int ipv4_connect(struct sockaddr_in *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 struct socket **csocket,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000102 char *netb_name,
103 char *server_netb_name);
104static int ipv6_connect(struct sockaddr_in6 *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 struct socket **csocket);
106
107
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000108 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000110 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 * mark tcp session as reconnecting so temporarily locked
112 * mark all smb sessions as reconnecting for tcp session
113 * reconnect tcp session
114 * wake up waiters on reconnection? - (not needed currently)
115 */
116
Steve French2cd646a2006-09-28 19:43:08 +0000117static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118cifs_reconnect(struct TCP_Server_Info *server)
119{
120 int rc = 0;
121 struct list_head *tmp;
122 struct cifsSesInfo *ses;
123 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000124 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000127 if (kthread_should_stop()) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000128 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 next time through the loop */
130 spin_unlock(&GlobalMid_Lock);
131 return rc;
132 } else
133 server->tcpStatus = CifsNeedReconnect;
134 spin_unlock(&GlobalMid_Lock);
135 server->maxBuf = 0;
136
Steve Frenche4eb2952005-04-28 22:41:09 -0700137 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139 /* before reconnecting the tcp session, mark the smb session (uid)
140 and the tid bad so they are not used until reconnected */
141 read_lock(&GlobalSMBSeslock);
142 list_for_each(tmp, &GlobalSMBSessionList) {
143 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
144 if (ses->server) {
145 if (ses->server == server) {
146 ses->status = CifsNeedReconnect;
147 ses->ipc_tid = 0;
148 }
149 }
150 /* else tcp and smb sessions need reconnection */
151 }
152 list_for_each(tmp, &GlobalTreeConnectionList) {
153 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve French26f57362007-08-30 22:09:15 +0000154 if ((tcon) && (tcon->ses) && (tcon->ses->server == server))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 tcon->tidStatus = CifsNeedReconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 }
157 read_unlock(&GlobalSMBSeslock);
158 /* do not want to be sending data on a socket we are freeing */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000159 down(&server->tcpSem);
160 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000161 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800163 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000164 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000165 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 server->ssocket->flags));
167 sock_release(server->ssocket);
168 server->ssocket = NULL;
169 }
170
171 spin_lock(&GlobalMid_Lock);
172 list_for_each(tmp, &server->pending_mid_q) {
173 mid_entry = list_entry(tmp, struct
174 mid_q_entry,
175 qhead);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000176 if (mid_entry) {
177 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700178 /* Mark other intransit requests as needing
179 retry so we do not immediately mark the
180 session bad again (ie after we reconnect
181 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 mid_entry->midState = MID_RETRY_NEEDED;
183 }
184 }
185 }
186 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000187 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Steve French26f57362007-08-30 22:09:15 +0000189 while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000190 try_to_freeze();
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000191 if (server->protocolType == IPV6) {
192 rc = ipv6_connect(&server->addr.sockAddr6,
193 &server->ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000195 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700197 server->workstation_RFC1001_name,
198 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000200 if (rc) {
201 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700202 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 } else {
204 atomic_inc(&tcpSesReconnectCount);
205 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000206 if (!kthread_should_stop())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700208 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000209 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 /* atomic_set(&server->inFlight,0);*/
211 wake_up(&server->response_q);
212 }
213 }
214 return rc;
215}
216
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000217/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700218 return codes:
219 0 not a transact2, or all data present
220 >0 transact2 with that much data missing
221 -EINVAL = invalid transact2
222
223 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000224static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700225{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000226 struct smb_t2_rsp *pSMBt;
227 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700228 int data_in_this_rsp;
229 int remaining;
230
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000231 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700232 return 0;
233
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000234 /* check for plausible wct, bcc and t2 data and parm sizes */
235 /* check for parm and data offset going beyond end of smb */
236 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000237 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700238 return -EINVAL;
239 }
240
241 pSMBt = (struct smb_t2_rsp *)pSMB;
242
243 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
244 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
245
246 remaining = total_data_size - data_in_this_rsp;
247
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000248 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700249 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000250 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000251 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700252 total_data_size, data_in_this_rsp));
253 return -EINVAL;
254 } else {
Steve French467a8f82007-06-27 22:41:32 +0000255 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700256 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000257 if (total_data_size > maxBufSize) {
258 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
259 total_data_size, maxBufSize));
260 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700261 }
262 return remaining;
263 }
264}
265
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000266static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700267{
268 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
269 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
270 int total_data_size;
271 int total_in_buf;
272 int remaining;
273 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000274 char *data_area_of_target;
275 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700276 __u16 byte_count;
277
278 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
279
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000280 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000281 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700282 }
283
284 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
285
286 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000287
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000288 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700289 return -EINVAL;
290
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000291 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700292 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000293
Steve Frenche4eb2952005-04-28 22:41:09 -0700294 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000295 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000296 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700297 }
298
299 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000300 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700301 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
302 /* validate target area */
303
304 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000305 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700306
307 data_area_of_target += total_in_buf;
308
309 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000310 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700311 total_in_buf += total_in_buf2;
312 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
313 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
314 byte_count += total_in_buf2;
315 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
316
Steve French70ca7342005-09-22 16:32:06 -0700317 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700318 byte_count += total_in_buf2;
319
320 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000321
Steve French70ca7342005-09-22 16:32:06 -0700322 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700323
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000324 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000325 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700326 return 0; /* we are done */
327 } else /* more responses to go */
328 return 1;
329
330}
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332static int
333cifs_demultiplex_thread(struct TCP_Server_Info *server)
334{
335 int length;
336 unsigned int pdu_length, total_read;
337 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700338 struct smb_hdr *bigbuf = NULL;
339 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 struct msghdr smb_msg;
341 struct kvec iov;
342 struct socket *csocket = server->ssocket;
343 struct list_head *tmp;
344 struct cifsSesInfo *ses;
345 struct task_struct *task_to_wake = NULL;
346 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700347 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700348 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700349 int isMultiRsp;
350 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 current->flags |= PF_MEMALLOC;
353 server->tsk = current; /* save process info to wake at shutdown */
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700354 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000355 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 atomic_inc(&tcpSesAllocCount);
357 length = tcpSesAllocCount.counter;
358 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700359 complete(&cifsd_complete);
Steve French26f57362007-08-30 22:09:15 +0000360 if (length > 1)
361 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
362 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700364 set_freezable();
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000365 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700366 if (try_to_freeze())
367 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700368 if (bigbuf == NULL) {
369 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000370 if (!bigbuf) {
371 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700372 msleep(3000);
373 /* retry will check if exiting */
374 continue;
375 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000376 } else if (isLargeBuf) {
377 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000378 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700380
381 if (smallbuf == NULL) {
382 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000383 if (!smallbuf) {
384 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700385 msleep(1000);
386 /* retry will check if exiting */
387 continue;
388 }
389 /* beginning of smb buffer is cleared in our buf_get */
390 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000391 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700392
393 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700394 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700395 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 iov.iov_base = smb_buffer;
397 iov.iov_len = 4;
398 smb_msg.msg_control = NULL;
399 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000400 pdu_length = 4; /* enough to get RFC1001 header */
401incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 length =
403 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000404 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Steve French26f57362007-08-30 22:09:15 +0000406 if (kthread_should_stop()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 break;
408 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000409 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000411 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 csocket = server->ssocket;
413 continue;
414 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700415 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 allowing socket to clear and app threads to set
417 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc18c7322007-10-17 18:01:11 +0000418 if (pdu_length < 4)
419 goto incomplete_rcv;
420 else
421 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000423 if (server->tcpStatus == CifsNew) {
424 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700425 /* some servers kill the TCP session rather than
426 returning an SMB negprot error, in which
427 case reconnecting here is not going to help,
428 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 break;
430 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000431 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000432 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 break;
434 }
Steve French467a8f82007-06-27 22:41:32 +0000435 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700436 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 cifs_reconnect(server);
438 csocket = server->ssocket;
439 wake_up(&server->response_q);
440 continue;
Steve French46810cb2005-04-28 22:41:09 -0700441 } else if (length < 4) {
Steve Frenchf01d5e12007-08-30 21:13:31 +0000442 cFYI(1, ("less than four bytes received (%d bytes)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000444 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000445 msleep(1);
446 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
Steve French67010fb2005-04-28 22:41:09 -0700448
Steve French70ca7342005-09-22 16:32:06 -0700449 /* The right amount was read from socket - 4 bytes */
450 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700451
Steve French70ca7342005-09-22 16:32:06 -0700452 /* the first byte big endian of the length field,
453 is actually not part of the length but the type
454 with the most common, zero, as regular data */
455 temp = *((char *) smb_buffer);
456
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000457 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700458 but we convert it here so it is always manipulated
459 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700460 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700461 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700462
Steve French467a8f82007-06-27 22:41:32 +0000463 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700464
465 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000466 continue;
Steve French70ca7342005-09-22 16:32:06 -0700467 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000468 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700469 continue;
Steve French70ca7342005-09-22 16:32:06 -0700470 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000471 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700472 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700474 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000475 if (server->tcpStatus == CifsNew) {
476 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700477 ret of smb negprot error) reconnecting
478 not going to help, ret error to mount */
479 break;
480 } else {
481 /* give server a second to
482 clean up before reconnect attempt */
483 msleep(1000);
484 /* always try 445 first on reconnect
485 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000486 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700487 since we do not begin with RFC1001
488 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000489 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700490 htons(CIFS_PORT);
491 cifs_reconnect(server);
492 csocket = server->ssocket;
493 wake_up(&server->response_q);
494 continue;
495 }
Steve French70ca7342005-09-22 16:32:06 -0700496 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000497 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700498 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
499 length);
Steve French46810cb2005-04-28 22:41:09 -0700500 cifs_reconnect(server);
501 csocket = server->ssocket;
502 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700503 }
504
505 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000506 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000507 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700508 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700509 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700510 cifs_reconnect(server);
511 csocket = server->ssocket;
512 wake_up(&server->response_q);
513 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000514 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700515
516 /* else length ok */
517 reconnect = 0;
518
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000519 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700520 isLargeBuf = TRUE;
521 memcpy(bigbuf, smallbuf, 4);
522 smb_buffer = bigbuf;
523 }
524 length = 0;
525 iov.iov_base = 4 + (char *)smb_buffer;
526 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000527 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700528 total_read += length) {
529 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
530 pdu_length - total_read, 0);
Steve French26f57362007-08-30 22:09:15 +0000531 if (kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700532 (length == -EINTR)) {
533 /* then will exit */
534 reconnect = 2;
535 break;
536 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700537 cifs_reconnect(server);
538 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000539 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700540 /* Now we will reread sock */
541 reconnect = 1;
542 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000543 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700544 (length == -EAGAIN)) {
545 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000546 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 threads to set tcpStatus
548 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000549 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700550 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000552 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700553 pdu_length - total_read));
554 cifs_reconnect(server);
555 csocket = server->ssocket;
556 reconnect = 1;
557 break;
Steve French46810cb2005-04-28 22:41:09 -0700558 }
559 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000560 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700561 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000562 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700563 continue;
564
565 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000566
Steve Frenche4eb2952005-04-28 22:41:09 -0700567
568 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000569 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700570 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700571 continue;
572 }
573
574
575 task_to_wake = NULL;
576 spin_lock(&GlobalMid_Lock);
577 list_for_each(tmp, &server->pending_mid_q) {
578 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
579
Steve French50c2f752007-07-13 00:33:32 +0000580 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
582 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000583 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700585 isMultiRsp = TRUE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000586 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000588 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000590 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 break;
592 } else {
593 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000594 mid_entry->multiEnd = 1;
Steve French50c2f752007-07-13 00:33:32 +0000595 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 }
597 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000598 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 cERROR(1,("1st trans2 resp needs bigbuf"));
600 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000601 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700602 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700603 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700604 mid_entry->resp_buf =
605 smb_buffer;
606 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700607 bigbuf = NULL;
608 }
609 }
610 break;
Steve French50c2f752007-07-13 00:33:32 +0000611 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700612 mid_entry->resp_buf = smb_buffer;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000613 if (isLargeBuf)
Steve Frenche4eb2952005-04-28 22:41:09 -0700614 mid_entry->largeBuf = 1;
615 else
616 mid_entry->largeBuf = 0;
617multi_t2_fnd:
618 task_to_wake = mid_entry->tsk;
619 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700620#ifdef CONFIG_CIFS_STATS2
621 mid_entry->when_received = jiffies;
622#endif
Steve French3a5ff612006-07-14 22:37:11 +0000623 /* so we do not time out requests to server
624 which is still responding (since server could
625 be busy but not dead) */
626 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700627 break;
628 }
629 }
630 spin_unlock(&GlobalMid_Lock);
631 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700632 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000633 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700634 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000635 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700636 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000637 else
Steve Frenchcd634992005-04-28 22:41:10 -0700638 smallbuf = NULL;
639 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700640 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000641 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve French50c2f752007-07-13 00:33:32 +0000642 && (isMultiRsp == FALSE)) {
643 cERROR(1, ("No task to wake, unknown frame received! "
644 "NumMids %d", midCount.counter));
645 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700646 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000647#ifdef CONFIG_CIFS_DEBUG2
648 cifs_dump_detail(smb_buffer);
649 cifs_dump_mids(server);
650#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000651
Steve Frenche4eb2952005-04-28 22:41:09 -0700652 }
653 } /* end while !EXITING */
654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 spin_lock(&GlobalMid_Lock);
656 server->tcpStatus = CifsExiting;
657 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700658 /* check if we have blocked requests that need to free */
659 /* Note that cifs_max_pending is normally 50, but
660 can be set at module install time to as little as two */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000661 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700662 atomic_set(&server->inFlight, cifs_max_pending - 1);
663 /* We do not want to set the max_pending too low or we
664 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000666 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700668 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 to the same server - they now will see the session is in exit state
670 and get out of SendReceive. */
671 wake_up_all(&server->request_q);
672 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700673 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000674
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000675 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 sock_release(csocket);
677 server->ssocket = NULL;
678 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700679 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000680 cifs_buf_release(bigbuf);
681 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700682 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 read_lock(&GlobalSMBSeslock);
685 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700686 /* loop through server session structures attached to this and
687 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 list_for_each(tmp, &GlobalSMBSessionList) {
689 ses =
690 list_entry(tmp, struct cifsSesInfo,
691 cifsSessionList);
692 if (ses->server == server) {
693 ses->status = CifsExiting;
694 ses->server = NULL;
695 }
696 }
697 read_unlock(&GlobalSMBSeslock);
698 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700699 /* although we can not zero the server struct pointer yet,
700 since there are active requests which may depnd on them,
701 mark the corresponding SMB sessions as exiting too */
702 list_for_each(tmp, &GlobalSMBSessionList) {
703 ses = list_entry(tmp, struct cifsSesInfo,
704 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000705 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700706 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700707 }
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 spin_lock(&GlobalMid_Lock);
710 list_for_each(tmp, &server->pending_mid_q) {
711 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
712 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000713 cFYI(1, ("Clearing Mid 0x%x - waking up ",
714 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000716 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
719 }
720 spin_unlock(&GlobalMid_Lock);
721 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700723 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725
Steve Frenchf1914012005-08-18 09:37:34 -0700726 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000727 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700729 /* due to delays on oplock break requests, we need
730 to wait at least 45 seconds before giving up
731 on a request getting a response and going ahead
732 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700734 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /* if threads still have not exited they are probably never
736 coming home not much else we can do but free the memory */
737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 write_lock(&GlobalSMBSeslock);
740 atomic_dec(&tcpSesAllocCount);
741 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700742
743 /* last chance to mark ses pointers invalid
744 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000745 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700746 kernel thread explicitly this might happen) */
747 list_for_each(tmp, &GlobalSMBSessionList) {
748 ses = list_entry(tmp, struct cifsSesInfo,
749 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000750 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700751 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700754
755 kfree(server);
Steve French26f57362007-08-30 22:09:15 +0000756 if (length > 0)
757 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
758 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return 0;
761}
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763static int
Steve French50c2f752007-07-13 00:33:32 +0000764cifs_parse_mount_options(char *options, const char *devname,
765 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
767 char *value;
768 char *data;
769 unsigned int temp_len, i, j;
770 char separator[2];
771
772 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000773 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Linus Torvalds12e36b22006-10-13 08:09:29 -0700775 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000776 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000777 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700778 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000779 int n = strnlen(nodename, 15);
780 memset(vol->source_rfc1001_name, 0x20, 15);
781 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000782 /* does not have to be perfect mapping since field is
783 informational, only used for servers that do not support
784 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700785 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 }
788 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700789 /* null target name indicates to use *SMBSERVR default called name
790 if we end up sending RFC1001 session initialize */
791 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 vol->linux_uid = current->uid; /* current->euid instead? */
793 vol->linux_gid = current->gid;
794 vol->dir_mode = S_IRWXUGO;
795 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000796 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
799 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700800 /* default is always to request posix paths. */
801 vol->posix_paths = 1;
802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (!options)
804 return 1;
805
Steve French50c2f752007-07-13 00:33:32 +0000806 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000807 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 separator[0] = options[4];
809 options += 5;
810 } else {
Steve French467a8f82007-06-27 22:41:32 +0000811 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 }
813 }
Steve French50c2f752007-07-13 00:33:32 +0000814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 while ((data = strsep(&options, separator)) != NULL) {
816 if (!*data)
817 continue;
818 if ((value = strchr(data, '=')) != NULL)
819 *value++ = '\0';
820
Steve French50c2f752007-07-13 00:33:32 +0000821 /* Have to parse this before we parse for "user" */
822 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000824 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 vol->no_xattr = 1;
826 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000827 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 printk(KERN_WARNING
829 "CIFS: invalid or missing username\n");
830 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000831 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000832 /* null user, ie anonymous, authentication */
833 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
835 if (strnlen(value, 200) < 200) {
836 vol->username = value;
837 } else {
838 printk(KERN_WARNING "CIFS: username too long\n");
839 return 1;
840 }
841 } else if (strnicmp(data, "pass", 4) == 0) {
842 if (!value) {
843 vol->password = NULL;
844 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000845 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 /* check if string begins with double comma
847 since that would mean the password really
848 does start with a comma, and would not
849 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000850 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 vol->password = NULL;
852 continue;
853 }
854 }
855 temp_len = strlen(value);
856 /* removed password length check, NTLM passwords
857 can be arbitrarily long */
858
Steve French50c2f752007-07-13 00:33:32 +0000859 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 prematurely null terminated. Commas in password are
861 specified across the cifs mount interface by a double
862 comma ie ,, and a comma used as in other cases ie ','
863 as a parameter delimiter/separator is single and due
864 to the strsep above is temporarily zeroed. */
865
866 /* NB: password legally can have multiple commas and
867 the only illegal character in a password is null */
868
Steve French50c2f752007-07-13 00:33:32 +0000869 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700870 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 /* reinsert comma */
872 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000873 temp_len += 2; /* move after second comma */
874 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000876 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700877 separator[0]) {
878 /* skip second comma */
879 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000880 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 /* single comma indicating start
882 of next parm */
883 break;
884 }
885 }
886 temp_len++;
887 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000888 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 options = NULL;
890 } else {
891 value[temp_len] = 0;
892 /* point option to start of next parm */
893 options = value + temp_len + 1;
894 }
Steve French50c2f752007-07-13 00:33:32 +0000895 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 double commas to singles. Note that this ends up
897 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700898 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000899 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000900 printk(KERN_WARNING "CIFS: no memory "
901 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700902 return 1;
903 }
Steve French50c2f752007-07-13 00:33:32 +0000904 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000906 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700907 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 /* skip second comma */
909 i++;
910 }
911 }
912 vol->password[j] = 0;
913 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700914 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000915 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000916 printk(KERN_WARNING "CIFS: no memory "
917 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700918 return 1;
919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 strcpy(vol->password, value);
921 }
922 } else if (strnicmp(data, "ip", 2) == 0) {
923 if (!value || !*value) {
924 vol->UNCip = NULL;
925 } else if (strnlen(value, 35) < 35) {
926 vol->UNCip = value;
927 } else {
Steve French50c2f752007-07-13 00:33:32 +0000928 printk(KERN_WARNING "CIFS: ip address "
929 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 return 1;
931 }
Steve French50c2f752007-07-13 00:33:32 +0000932 } else if (strnicmp(data, "sec", 3) == 0) {
933 if (!value || !*value) {
934 cERROR(1, ("no security value specified"));
935 continue;
936 } else if (strnicmp(value, "krb5i", 5) == 0) {
937 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000938 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800939 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000940 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
941 CIFSSEC_MAY_KRB5; */
942 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800943 return 1;
944 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000945 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800946 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000947 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000948 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800949 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000950 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800951 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000952 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000953 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800954 } else if (strnicmp(value, "ntlm", 4) == 0) {
955 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000956 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800957 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000958 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000959 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000960#ifdef CONFIG_CIFS_WEAK_PW_HASH
961 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000962 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000963#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800964 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000965 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000966 } else {
967 cERROR(1, ("bad security option: %s", value));
968 return 1;
969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 } else if ((strnicmp(data, "unc", 3) == 0)
971 || (strnicmp(data, "target", 6) == 0)
972 || (strnicmp(data, "path", 4) == 0)) {
973 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +0000974 printk(KERN_WARNING "CIFS: invalid path to "
975 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 return 1; /* needs_arg; */
977 }
978 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +0000979 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000980 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return 1;
Steve French50c2f752007-07-13 00:33:32 +0000982 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (strncmp(vol->UNC, "//", 2) == 0) {
984 vol->UNC[0] = '\\';
985 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +0000986 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +0000988 "CIFS: UNC Path does not begin "
989 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 return 1;
991 }
992 } else {
993 printk(KERN_WARNING "CIFS: UNC name too long\n");
994 return 1;
995 }
996 } else if ((strnicmp(data, "domain", 3) == 0)
997 || (strnicmp(data, "workgroup", 5) == 0)) {
998 if (!value || !*value) {
999 printk(KERN_WARNING "CIFS: invalid domain name\n");
1000 return 1; /* needs_arg; */
1001 }
1002 /* BB are there cases in which a comma can be valid in
1003 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001004 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 vol->domainname = value;
1006 cFYI(1, ("Domain name set"));
1007 } else {
Steve French50c2f752007-07-13 00:33:32 +00001008 printk(KERN_WARNING "CIFS: domain name too "
1009 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return 1;
1011 }
Steve French50c2f752007-07-13 00:33:32 +00001012 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1013 if (!value || !*value) {
1014 printk(KERN_WARNING
1015 "CIFS: invalid path prefix\n");
1016 return 1; /* needs_argument */
1017 }
1018 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001019 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001020 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001021 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1022 if (vol->prepath == NULL)
1023 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001024 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001025 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001026 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001027 } else
Steve French50c2f752007-07-13 00:33:32 +00001028 strcpy(vol->prepath, value);
1029 cFYI(1, ("prefix path %s", vol->prepath));
1030 } else {
1031 printk(KERN_WARNING "CIFS: prefix too long\n");
1032 return 1;
1033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 } else if (strnicmp(data, "iocharset", 9) == 0) {
1035 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001036 printk(KERN_WARNING "CIFS: invalid iocharset "
1037 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return 1; /* needs_arg; */
1039 }
1040 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001041 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001043 /* if iocharset not set then load_nls_default
1044 is used by caller */
1045 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 } else {
Steve French63135e02007-07-17 17:34:02 +00001047 printk(KERN_WARNING "CIFS: iocharset name "
1048 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 return 1;
1050 }
1051 } else if (strnicmp(data, "uid", 3) == 0) {
1052 if (value && *value) {
1053 vol->linux_uid =
1054 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001055 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057 } else if (strnicmp(data, "gid", 3) == 0) {
1058 if (value && *value) {
1059 vol->linux_gid =
1060 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001061 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
1063 } else if (strnicmp(data, "file_mode", 4) == 0) {
1064 if (value && *value) {
1065 vol->file_mode =
1066 simple_strtoul(value, &value, 0);
1067 }
1068 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1069 if (value && *value) {
1070 vol->dir_mode =
1071 simple_strtoul(value, &value, 0);
1072 }
1073 } else if (strnicmp(data, "dirmode", 4) == 0) {
1074 if (value && *value) {
1075 vol->dir_mode =
1076 simple_strtoul(value, &value, 0);
1077 }
1078 } else if (strnicmp(data, "port", 4) == 0) {
1079 if (value && *value) {
1080 vol->port =
1081 simple_strtoul(value, &value, 0);
1082 }
1083 } else if (strnicmp(data, "rsize", 5) == 0) {
1084 if (value && *value) {
1085 vol->rsize =
1086 simple_strtoul(value, &value, 0);
1087 }
1088 } else if (strnicmp(data, "wsize", 5) == 0) {
1089 if (value && *value) {
1090 vol->wsize =
1091 simple_strtoul(value, &value, 0);
1092 }
1093 } else if (strnicmp(data, "sockopt", 5) == 0) {
1094 if (value && *value) {
1095 vol->sockopt =
1096 simple_strtoul(value, &value, 0);
1097 }
1098 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1099 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001100 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 } else {
Steve French50c2f752007-07-13 00:33:32 +00001102 memset(vol->source_rfc1001_name, 0x20, 15);
1103 for (i = 0; i < 15; i++) {
1104 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 valid in this workstation netbios name (and need
1106 special handling)? */
1107
1108 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001109 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 break;
Steve French50c2f752007-07-13 00:33:32 +00001111 else
1112 vol->source_rfc1001_name[i] =
1113 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115 /* The string has 16th byte zero still from
1116 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001117 if ((i == 15) && (value[i] != 0))
1118 printk(KERN_WARNING "CIFS: netbiosname"
1119 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001120 }
1121 } else if (strnicmp(data, "servern", 7) == 0) {
1122 /* servernetbiosname specified override *SMBSERVER */
1123 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001124 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001125 } else {
1126 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001127 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001128
Steve French50c2f752007-07-13 00:33:32 +00001129 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001130 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001131 valid in this workstation netbios name
1132 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001133
Steve French50c2f752007-07-13 00:33:32 +00001134 /* user or mount helper must uppercase
1135 the netbiosname */
1136 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001137 break;
1138 else
Steve French50c2f752007-07-13 00:33:32 +00001139 vol->target_rfc1001_name[i] =
1140 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001141 }
1142 /* The string has 16th byte zero still from
1143 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001144 if ((i == 15) && (value[i] != 0))
1145 printk(KERN_WARNING "CIFS: server net"
1146 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148 } else if (strnicmp(data, "credentials", 4) == 0) {
1149 /* ignore */
1150 } else if (strnicmp(data, "version", 3) == 0) {
1151 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001152 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 /* ignore */
1154 } else if (strnicmp(data, "rw", 2) == 0) {
1155 vol->rw = TRUE;
1156 } else if ((strnicmp(data, "suid", 4) == 0) ||
1157 (strnicmp(data, "nosuid", 6) == 0) ||
1158 (strnicmp(data, "exec", 4) == 0) ||
1159 (strnicmp(data, "noexec", 6) == 0) ||
1160 (strnicmp(data, "nodev", 5) == 0) ||
1161 (strnicmp(data, "noauto", 6) == 0) ||
1162 (strnicmp(data, "dev", 3) == 0)) {
1163 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001164 uses these opts to set flags, and the flags are read
1165 by the kernel vfs layer before we get here (ie
1166 before read super) so there is no point trying to
1167 parse these options again and set anything and it
1168 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 continue;
1170 } else if (strnicmp(data, "ro", 2) == 0) {
1171 vol->rw = FALSE;
1172 } else if (strnicmp(data, "hard", 4) == 0) {
1173 vol->retry = 1;
1174 } else if (strnicmp(data, "soft", 4) == 0) {
1175 vol->retry = 0;
1176 } else if (strnicmp(data, "perm", 4) == 0) {
1177 vol->noperm = 0;
1178 } else if (strnicmp(data, "noperm", 6) == 0) {
1179 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001180 } else if (strnicmp(data, "mapchars", 8) == 0) {
1181 vol->remap = 1;
1182 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1183 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001184 } else if (strnicmp(data, "sfu", 3) == 0) {
1185 vol->sfu_emul = 1;
1186 } else if (strnicmp(data, "nosfu", 5) == 0) {
1187 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001188 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1189 vol->posix_paths = 1;
1190 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1191 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001192 } else if (strnicmp(data, "nounix", 6) == 0) {
1193 vol->no_linux_ext = 1;
1194 } else if (strnicmp(data, "nolinux", 7) == 0) {
1195 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001196 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001197 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001198 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001199 } else if (strnicmp(data, "brl", 3) == 0) {
1200 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001201 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001202 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001203 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001204 /* turn off mandatory locking in mode
1205 if remote locking is turned off since the
1206 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001207 if (vol->file_mode ==
1208 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001209 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 } else if (strnicmp(data, "setuids", 7) == 0) {
1211 vol->setuids = 1;
1212 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1213 vol->setuids = 0;
1214 } else if (strnicmp(data, "nohard", 6) == 0) {
1215 vol->retry = 0;
1216 } else if (strnicmp(data, "nosoft", 6) == 0) {
1217 vol->retry = 1;
1218 } else if (strnicmp(data, "nointr", 6) == 0) {
1219 vol->intr = 0;
1220 } else if (strnicmp(data, "intr", 4) == 0) {
1221 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001222 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001224 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001226 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001227 vol->cifs_acl = 1;
1228 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1229 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001230 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001232 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001234 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001235 vol->secFlg |= CIFSSEC_MUST_SIGN;
1236/* } else if (strnicmp(data, "seal",4) == 0) {
1237 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Steve French50c2f752007-07-13 00:33:32 +00001238 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001240 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001242 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (!value || !*value) {
1244 vol->in6_addr = NULL;
1245 } else if (strnlen(value, 49) == 48) {
1246 vol->in6_addr = value;
1247 } else {
Steve French50c2f752007-07-13 00:33:32 +00001248 printk(KERN_WARNING "CIFS: ip v6 address not "
1249 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 return 1;
1251 }
1252 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001253 printk(KERN_WARNING "CIFS: Mount option noac not "
1254 "supported. Instead set "
1255 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 } else
Steve French50c2f752007-07-13 00:33:32 +00001257 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1258 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001261 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001262 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1263 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 return 1;
1265 }
1266 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001267 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001268 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001270 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 if (strncmp(vol->UNC, "//", 2) == 0) {
1272 vol->UNC[0] = '\\';
1273 vol->UNC[1] = '\\';
1274 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001275 printk(KERN_WARNING "CIFS: UNC Path does not "
1276 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 return 1;
1278 }
1279 } else {
1280 printk(KERN_WARNING "CIFS: UNC name too long\n");
1281 return 1;
1282 }
1283 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001284 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 vol->UNCip = &vol->UNC[2];
1286
1287 return 0;
1288}
1289
1290static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001291cifs_find_tcp_session(struct in_addr *target_ip_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 struct in6_addr *target_ip6_addr,
1293 char *userName, struct TCP_Server_Info **psrvTcp)
1294{
1295 struct list_head *tmp;
1296 struct cifsSesInfo *ses;
1297 *psrvTcp = NULL;
1298 read_lock(&GlobalSMBSeslock);
1299
1300 list_for_each(tmp, &GlobalSMBSessionList) {
1301 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1302 if (ses->server) {
Steve French50c2f752007-07-13 00:33:32 +00001303 if ((target_ip_addr &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 (ses->server->addr.sockAddr.sin_addr.s_addr
1305 == target_ip_addr->s_addr)) || (target_ip6_addr
1306 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
Steve French50c2f752007-07-13 00:33:32 +00001307 target_ip6_addr, sizeof(*target_ip6_addr)))) {
1308 /* BB lock server and tcp session and increment
1309 use count here?? */
1310
1311 /* found a match on the TCP session */
1312 *psrvTcp = ses->server;
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 /* BB check if reconnection needed */
1315 if (strncmp
1316 (ses->userName, userName,
1317 MAX_USERNAME_SIZE) == 0){
1318 read_unlock(&GlobalSMBSeslock);
Steve French50c2f752007-07-13 00:33:32 +00001319 /* Found exact match on both TCP and
1320 SMB sessions */
1321 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 }
1323 }
1324 }
1325 /* else tcp and smb sessions need reconnection */
1326 }
1327 read_unlock(&GlobalSMBSeslock);
1328 return NULL;
1329}
1330
1331static struct cifsTconInfo *
1332find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1333{
1334 struct list_head *tmp;
1335 struct cifsTconInfo *tcon;
1336
1337 read_lock(&GlobalSMBSeslock);
1338 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001339 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1341 if (tcon->ses) {
1342 if (tcon->ses->server) {
1343 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001344 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 tcon->ses->server->addr.sockAddr.sin_addr.
1346 s_addr, new_target_ip_addr));
1347 if (tcon->ses->server->addr.sockAddr.sin_addr.
1348 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001349 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 /* found a match on the TCP session */
1351 /* BB check if reconnection needed */
Steve French50c2f752007-07-13 00:33:32 +00001352 cFYI(1,
1353 ("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 tcon->treeName, uncName));
1355 if (strncmp
1356 (tcon->treeName, uncName,
1357 MAX_TREE_SIZE) == 0) {
1358 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001359 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 tcon->treeName, uncName));
1361 if (strncmp
1362 (tcon->ses->userName,
1363 userName,
1364 MAX_USERNAME_SIZE) == 0) {
1365 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001366 /* matched smb session
1367 (user name */
1368 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
1370 }
1371 }
1372 }
1373 }
1374 }
1375 read_unlock(&GlobalSMBSeslock);
1376 return NULL;
1377}
1378
1379int
1380connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001381 const char *old_path, const struct nls_table *nls_codepage,
1382 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383{
1384 unsigned char *referrals = NULL;
1385 unsigned int num_referrals;
1386 int rc = 0;
1387
Steve French50c2f752007-07-13 00:33:32 +00001388 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001389 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
1391 /* BB Add in code to: if valid refrl, if not ip address contact
Steve French50c2f752007-07-13 00:33:32 +00001392 the helper that resolves tcp names, mount to it, try to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 tcon to it unmount it if fail */
1394
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001395 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
1397 return rc;
1398}
1399
1400int
Steve French50c2f752007-07-13 00:33:32 +00001401get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1402 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1403 unsigned char **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404{
1405 char *temp_unc;
1406 int rc = 0;
1407
1408 *pnum_referrals = 0;
1409
1410 if (pSesInfo->ipc_tid == 0) {
1411 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001412 strnlen(pSesInfo->serverName,
1413 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 + 1 + 4 /* slash IPC$ */ + 2,
1415 GFP_KERNEL);
1416 if (temp_unc == NULL)
1417 return -ENOMEM;
1418 temp_unc[0] = '\\';
1419 temp_unc[1] = '\\';
1420 strcpy(temp_unc + 2, pSesInfo->serverName);
1421 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1422 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1423 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001424 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 kfree(temp_unc);
1426 }
1427 if (rc == 0)
1428 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001429 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431 return rc;
1432}
1433
1434/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001435static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436{
Steve French50c2f752007-07-13 00:33:32 +00001437 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Steve French50c2f752007-07-13 00:33:32 +00001439 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 /* mask a nibble at a time and encode */
1441 target[j] = 'A' + (0x0F & (source[i] >> 4));
1442 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001443 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 }
1445
1446}
1447
1448
1449static int
Steve French50c2f752007-07-13 00:33:32 +00001450ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1451 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452{
1453 int rc = 0;
1454 int connected = 0;
1455 __be16 orig_port = 0;
1456
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001457 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001458 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1459 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001461 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 *csocket = NULL;
1463 return rc;
1464 } else {
1465 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001466 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001467 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
1469 }
1470
1471 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001472 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 rc = (*csocket)->ops->connect(*csocket,
1474 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001475 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (rc >= 0)
1477 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001480 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001481 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 later if fall back ports fail this time */
1483 orig_port = psin_server->sin_port;
1484
1485 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001486 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 psin_server->sin_port = htons(CIFS_PORT);
1488
1489 rc = (*csocket)->ops->connect(*csocket,
1490 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001491 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 if (rc >= 0)
1493 connected = 1;
1494 }
1495 }
1496 if (!connected) {
1497 psin_server->sin_port = htons(RFC1001_PORT);
1498 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001499 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001500 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001501 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 connected = 1;
1503 }
1504
1505 /* give up here - unless we want to retry on different
1506 protocol families some day */
1507 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001508 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001510 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 sock_release(*csocket);
1512 *csocket = NULL;
1513 return rc;
1514 }
Steve French50c2f752007-07-13 00:33:32 +00001515 /* Eventually check for other socket options to change from
1516 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001518 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1519 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001520 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001522 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001523 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001524 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001525 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001526 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001529 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001531 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001533 struct rfc1002_session_packet *ses_init_buf;
1534 struct smb_hdr *smb_buf;
1535 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1536 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001537 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001539 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001540 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1541 target_name, 16);
1542 } else {
1543 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001544 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001545 }
1546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 ses_init_buf->trailer.session_req.calling_len = 32;
1548 /* calling name ends in null (byte 16) from old smb
1549 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001550 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001552 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 } else {
1554 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001555 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 }
1557 ses_init_buf->trailer.session_req.scope1 = 0;
1558 ses_init_buf->trailer.session_req.scope2 = 0;
1559 smb_buf = (struct smb_hdr *)ses_init_buf;
1560 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1561 smb_buf->smb_buf_length = 0x81000044;
1562 rc = smb_send(*csocket, smb_buf, 0x44,
1563 (struct sockaddr *)psin_server);
1564 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001565 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001566 requires very short break before negprot
1567 presumably because not expecting negprot
1568 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001569 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001570 complicating the code and causes no
1571 significant slowing down on mount
1572 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
Steve French50c2f752007-07-13 00:33:32 +00001574 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
Steve French50c2f752007-07-13 00:33:32 +00001578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 return rc;
1580}
1581
1582static int
1583ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1584{
1585 int rc = 0;
1586 int connected = 0;
1587 __be16 orig_port = 0;
1588
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001589 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001590 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1591 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001593 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 *csocket = NULL;
1595 return rc;
1596 } else {
1597 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001598 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 (*csocket)->sk->sk_allocation = GFP_NOFS;
1600 }
1601 }
1602
1603 psin_server->sin6_family = AF_INET6;
1604
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001605 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 rc = (*csocket)->ops->connect(*csocket,
1607 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001608 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 if (rc >= 0)
1610 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001613 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001614 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 later if fall back ports fail this time */
1616
1617 orig_port = psin_server->sin6_port;
1618 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001619 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 psin_server->sin6_port = htons(CIFS_PORT);
1621
1622 rc = (*csocket)->ops->connect(*csocket,
1623 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001624 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 if (rc >= 0)
1626 connected = 1;
1627 }
1628 }
1629 if (!connected) {
1630 psin_server->sin6_port = htons(RFC1001_PORT);
1631 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001632 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001633 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 connected = 1;
1635 }
1636
1637 /* give up here - unless we want to retry on different
1638 protocol families some day */
1639 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001640 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001642 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 sock_release(*csocket);
1644 *csocket = NULL;
1645 return rc;
1646 }
Steve French50c2f752007-07-13 00:33:32 +00001647 /* Eventually check for other socket options to change from
1648 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 user space buffer */
1650 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001651
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 return rc;
1653}
1654
Steve French50c2f752007-07-13 00:33:32 +00001655void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1656 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001657{
1658 /* if we are reconnecting then should we check to see if
1659 * any requested capabilities changed locally e.g. via
1660 * remount but we can not do much about it here
1661 * if they have (even if we could detect it by the following)
1662 * Perhaps we could add a backpointer to array of sb from tcon
1663 * or if we change to make all sb to same share the same
1664 * sb as NFS - then we only have one backpointer to sb.
1665 * What if we wanted to mount the server share twice once with
1666 * and once without posixacls or posix paths? */
1667 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001668
Steve Frenchc18c8422007-07-18 23:21:09 +00001669 if (vol_info && vol_info->no_linux_ext) {
1670 tcon->fsUnixInfo.Capability = 0;
1671 tcon->unix_ext = 0; /* Unix Extensions disabled */
1672 cFYI(1, ("Linux protocol extensions disabled"));
1673 return;
1674 } else if (vol_info)
1675 tcon->unix_ext = 1; /* Unix Extensions supported */
1676
1677 if (tcon->unix_ext == 0) {
1678 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1679 return;
1680 }
Steve French50c2f752007-07-13 00:33:32 +00001681
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001682 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001683 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001684
Steve French8af18972007-02-14 04:42:51 +00001685 /* check for reconnect case in which we do not
1686 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001687 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001688 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001689 originally at mount time */
1690 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1691 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1692 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1693 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French8af18972007-02-14 04:42:51 +00001694 }
Steve French50c2f752007-07-13 00:33:32 +00001695
Steve French8af18972007-02-14 04:42:51 +00001696 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001697 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001698 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001699 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001700 cFYI(1, ("negotiated posix acl support"));
1701 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001702 sb->s_flags |= MS_POSIXACL;
1703 }
1704
Steve French75865f8c2007-06-24 18:30:48 +00001705 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001706 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001707 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001708 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001709 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001710 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001711 CIFS_MOUNT_POSIX_PATHS;
1712 }
Steve French50c2f752007-07-13 00:33:32 +00001713
Steve French984acfe2007-04-26 16:42:50 +00001714 /* We might be setting the path sep back to a different
1715 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001716 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001717 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001718 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001719
1720 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1721 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1722 CIFS_SB(sb)->rsize = 127 * 1024;
1723#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001724 cFYI(1, ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001725#endif
1726 }
1727 }
Steve French50c2f752007-07-13 00:33:32 +00001728
1729
1730 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001731#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001732 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001733 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001734 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001735 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001736 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001737 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001738 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001739 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001740 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001741 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001742 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001743 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001744 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001745 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001746#endif /* CIFS_DEBUG2 */
1747 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001748 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001749 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001750 } else
Steve French5a44b312007-09-20 15:16:24 +00001751 cERROR(1, ("Negotiating Unix capabilities "
1752 "with the server failed. Consider "
1753 "mounting with the Unix Extensions\n"
1754 "disabled, if problems are found, "
1755 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001756 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001757
Steve French8af18972007-02-14 04:42:51 +00001758 }
1759 }
1760}
1761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762int
1763cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1764 char *mount_data, const char *devname)
1765{
1766 int rc = 0;
1767 int xid;
1768 int address_type = AF_INET;
1769 struct socket *csocket = NULL;
1770 struct sockaddr_in sin_server;
1771 struct sockaddr_in6 sin_server6;
1772 struct smb_vol volume_info;
1773 struct cifsSesInfo *pSesInfo = NULL;
1774 struct cifsSesInfo *existingCifsSes = NULL;
1775 struct cifsTconInfo *tcon = NULL;
1776 struct TCP_Server_Info *srvTcp = NULL;
1777
1778 xid = GetXid();
1779
1780/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001781
1782 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001784 rc = -EINVAL;
1785 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 }
1787
Jeff Layton8426c392007-05-05 03:27:49 +00001788 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001789 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001790 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001791 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001793 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001795 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001796 /* In userspace mount helper we can get user name from alternate
1797 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001798 rc = -EINVAL;
1799 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 }
1801
1802 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001803 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1804 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001806 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001808 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1809 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001810 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 address_type = AF_INET6;
1812 } else {
1813 address_type = AF_INET;
1814 }
Steve French50c2f752007-07-13 00:33:32 +00001815
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001816 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001818 rc = -EINVAL;
1819 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 }
1821
1822 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1823 /* success */
1824 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001825 } else if (volume_info.UNCip) {
1826 /* BB using ip addr as server name to connect to the
1827 DFS root below */
1828 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001829 rc = -EINVAL;
1830 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 } else /* which servers DFS root would we conect to */ {
1832 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001833 ("CIFS mount error: No UNC path (e.g. -o "
1834 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001835 rc = -EINVAL;
1836 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 }
1838
1839 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001840 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 cifs_sb->local_nls = load_nls_default();
1842 /* load_nls_default can not return null */
1843 } else {
1844 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001845 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001846 cERROR(1, ("CIFS mount error: iocharset %s not found",
1847 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001848 rc = -ELIBACC;
1849 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 }
1851 }
1852
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001853 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1855 NULL /* no ipv6 addr */,
1856 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001857 else if (address_type == AF_INET6) {
1858 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1860 &sin_server6.sin6_addr,
1861 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001862 } else {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001863 rc = -EINVAL;
1864 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 }
1866
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001868 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001870 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 sin_server.sin_port = htons(volume_info.port);
1872 else
1873 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001874 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001875 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001876 /* BB should we allow ipv6 on port 139? */
1877 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001878 rc = ipv6_connect(&sin_server6, &csocket);
1879 } else
1880 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001881 volume_info.source_rfc1001_name,
1882 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001884 cERROR(1, ("Error connecting to IPv4 socket. "
1885 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001886 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001888 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 }
1890
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001891 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1892 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 rc = -ENOMEM;
1894 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001895 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 } else {
Steve French50c2f752007-07-13 00:33:32 +00001897 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001898 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00001899 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 /* BB Add code for ipv6 case too */
1901 srvTcp->ssocket = csocket;
1902 srvTcp->protocolType = IPV4;
1903 init_waitqueue_head(&srvTcp->response_q);
1904 init_waitqueue_head(&srvTcp->request_q);
1905 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1906 /* at this point we are the only ones with the pointer
1907 to the struct since the kernel thread not created yet
1908 so no need to spinlock this init of tcpStatus */
1909 srvTcp->tcpStatus = CifsNew;
1910 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001911 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001912 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001913 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001914 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001915 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001917 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07001918 }
1919 wait_for_completion(&cifsd_complete);
1920 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001921 memcpy(srvTcp->workstation_RFC1001_name,
1922 volume_info.source_rfc1001_name, 16);
1923 memcpy(srvTcp->server_RFC1001_name,
1924 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001925 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 }
1927 }
1928
1929 if (existingCifsSes) {
1930 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001931 cFYI(1, ("Existing smb sess found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001933 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 pSesInfo = sesInfoAlloc();
1935 if (pSesInfo == NULL)
1936 rc = -ENOMEM;
1937 else {
1938 pSesInfo->server = srvTcp;
1939 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1940 NIPQUAD(sin_server.sin_addr.s_addr));
1941 }
1942
Steve French50c2f752007-07-13 00:33:32 +00001943 if (!rc) {
1944 /* volume_info.password freed at unmount */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001945 if (volume_info.password) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 pSesInfo->password = volume_info.password;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001947 /* set to NULL to prevent freeing on exit */
1948 volume_info.password = NULL;
1949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 if (volume_info.username)
1951 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00001952 volume_info.username,
1953 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001954 if (volume_info.domainname) {
1955 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00001956 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00001957 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001958 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001959 strcpy(pSesInfo->domainName,
1960 volume_info.domainname);
1961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001963 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001965 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00001966 rc = cifs_setup_session(xid, pSesInfo,
1967 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001969 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 atomic_inc(&srvTcp->socketUseCount);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 }
Steve French50c2f752007-07-13 00:33:32 +00001973
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 /* search for existing tcon to this server share */
1975 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00001976 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00001977 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07001978 volume_info.rsize));
1979 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00001980 } else if ((volume_info.rsize) &&
1981 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001983 else /* default */
1984 cifs_sb->rsize = CIFSMaxBufSize;
1985
Steve French4523cc32007-04-30 20:13:06 +00001986 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00001987 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07001988 volume_info.wsize));
1989 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00001990 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 cifs_sb->wsize = volume_info.wsize;
1992 else
Steve French50c2f752007-07-13 00:33:32 +00001993 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08001994 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1995 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08001996 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00001997 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08001998 RFC1001 does not describe what happens when frame
1999 bigger than 128K is sent so use that as max in
2000 conjunction with 52K kvec constraint on arch with 4K
2001 page size */
2002
Steve French4523cc32007-04-30 20:13:06 +00002003 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002004 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002005 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002006 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 }
Steve French2fe87f02006-09-21 07:02:52 +00002008 /* calculate prepath */
2009 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002010 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002011 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2012 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
2013 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002014 } else
Steve French2fe87f02006-09-21 07:02:52 +00002015 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 cifs_sb->mnt_uid = volume_info.linux_uid;
2017 cifs_sb->mnt_gid = volume_info.linux_gid;
2018 cifs_sb->mnt_file_mode = volume_info.file_mode;
2019 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002020 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2021 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
Steve French4523cc32007-04-30 20:13:06 +00002023 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002025 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002027 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002029 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002030 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002031 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002033 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002034 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002035 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002036 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002037 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002038 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002039 if (volume_info.override_uid)
2040 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2041 if (volume_info.override_gid)
2042 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2043 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002044 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2046 }
2047
2048 tcon =
2049 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2050 volume_info.username);
2051 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002052 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 /* we can have only one retry value for a connection
2054 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002055 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 for the retry flag is used */
2057 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002058 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 } else {
2060 tcon = tconInfoAlloc();
2061 if (tcon == NULL)
2062 rc = -ENOMEM;
2063 else {
Steve French50c2f752007-07-13 00:33:32 +00002064 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002065 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Steve French50c2f752007-07-13 00:33:32 +00002067 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002068 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2070 && (strchr(volume_info.UNC + 3, '/') ==
2071 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002072 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002073 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002074 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002075 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002076 rc = -ENODEV;
2077 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 } else {
Steve French8af18972007-02-14 04:42:51 +00002079 /* BB Do we need to wrap sesSem around
2080 * this TCon call and Unix SetFS as
2081 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002082 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 volume_info.UNC,
2084 tcon, cifs_sb->local_nls);
2085 cFYI(1, ("CIFS Tcon rc = %d", rc));
2086 }
2087 if (!rc) {
2088 atomic_inc(&pSesInfo->inUse);
2089 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002090 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 }
2092 }
2093 }
2094 }
Steve French4523cc32007-04-30 20:13:06 +00002095 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2097 sb->s_maxbytes = (u64) 1 << 63;
2098 } else
2099 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2100 }
2101
Steve French8af18972007-02-14 04:42:51 +00002102 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 sb->s_time_gran = 100;
2104
2105/* on error free sesinfo and tcon struct if needed */
2106 if (rc) {
2107 /* if session setup failed, use count is zero but
2108 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002109 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 spin_lock(&GlobalMid_Lock);
2111 srvTcp->tcpStatus = CifsExiting;
2112 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002113 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002114 struct task_struct *tsk;
2115 /* If we could verify that kthread_stop would
2116 always wake up processes blocked in
2117 tcp in recv_mesg then we could remove the
2118 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002119 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002120 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002121 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002122 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 }
2125 /* If find_unc succeeded then rc == 0 so we can not end */
2126 if (tcon) /* up accidently freeing someone elses tcon struct */
2127 tconInfoFree(tcon);
2128 if (existingCifsSes == NULL) {
2129 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002130 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 (pSesInfo->status == CifsGood)) {
2132 int temp_rc;
2133 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2134 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002135 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002136 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002137 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002138 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002139 force_sig(SIGKILL,
2140 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002141 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002142 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002143 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002144 }
Steve Frencha0136892007-10-04 20:05:09 +00002145 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 cFYI(1, ("No session or bad tcon"));
Steve Frencha0136892007-10-04 20:05:09 +00002147 if ((pSesInfo->server) &&
2148 (pSesInfo->server->tsk)) {
2149 struct task_struct *tsk;
2150 force_sig(SIGKILL,
2151 pSesInfo->server->tsk);
2152 tsk = pSesInfo->server->tsk;
2153 if (tsk)
2154 kthread_stop(tsk);
2155 }
2156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 sesInfoFree(pSesInfo);
2158 /* pSesInfo = NULL; */
2159 }
2160 }
2161 } else {
2162 atomic_inc(&tcon->useCount);
2163 cifs_sb->tcon = tcon;
2164 tcon->ses = pSesInfo;
2165
Steve French82940a42006-03-02 03:24:57 +00002166 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002167 if (!tcon->ipc) {
2168 CIFSSMBQFSDeviceInfo(xid, tcon);
2169 CIFSSMBQFSAttributeInfo(xid, tcon);
2170 }
Steve French50c2f752007-07-13 00:33:32 +00002171
Steve French8af18972007-02-14 04:42:51 +00002172 /* tell server which Unix caps we support */
2173 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002174 /* reset of caps checks mount to see if unix extensions
2175 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002176 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002177 else
2178 tcon->unix_ext = 0; /* server does not support them */
2179
2180 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002181 cifs_sb->rsize = 1024 * 127;
2182#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchc18c8422007-07-18 23:21:09 +00002183 cFYI(1, ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002184#endif
Steve French75865f8c2007-06-24 18:30:48 +00002185 }
Steve French3e844692005-10-03 13:37:24 -07002186 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2187 cifs_sb->wsize = min(cifs_sb->wsize,
2188 (tcon->ses->server->maxBuf -
2189 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002190 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002191 cifs_sb->rsize = min(cifs_sb->rsize,
2192 (tcon->ses->server->maxBuf -
2193 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 }
2195
2196 /* volume_info.password is freed above when existing session found
2197 (in which case it is not needed anymore) but when new sesion is created
2198 the password ptr is put in the new session structure (in which case the
2199 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002200out:
2201 /* zero out password before freeing */
2202 if (volume_info.password != NULL) {
2203 memset(volume_info.password, 0, strlen(volume_info.password));
2204 kfree(volume_info.password);
2205 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002206 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002207 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 FreeXid(xid);
2209 return rc;
2210}
2211
2212static int
2213CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002214 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 const struct nls_table *nls_codepage)
2216{
2217 struct smb_hdr *smb_buffer;
2218 struct smb_hdr *smb_buffer_response;
2219 SESSION_SETUP_ANDX *pSMB;
2220 SESSION_SETUP_ANDX *pSMBr;
2221 char *bcc_ptr;
2222 char *user;
2223 char *domain;
2224 int rc = 0;
2225 int remaining_words = 0;
2226 int bytes_returned = 0;
2227 int len;
2228 __u32 capabilities;
2229 __u16 count;
2230
Steve Frencheeac8042006-01-13 21:34:58 -08002231 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002232 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 return -EINVAL;
2234 user = ses->userName;
2235 domain = ses->domainName;
2236 smb_buffer = cifs_buf_get();
2237 if (smb_buffer == NULL) {
2238 return -ENOMEM;
2239 }
2240 smb_buffer_response = smb_buffer;
2241 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2242
2243 /* send SMBsessionSetup here */
2244 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2245 NULL /* no tCon exists yet */ , 13 /* wct */ );
2246
Steve French1982c342005-08-17 12:38:22 -07002247 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 pSMB->req_no_secext.AndXCommand = 0xFF;
2249 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2250 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2251
Steve French50c2f752007-07-13 00:33:32 +00002252 if (ses->server->secMode &
2253 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2255
2256 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2257 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2258 if (ses->capabilities & CAP_UNICODE) {
2259 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2260 capabilities |= CAP_UNICODE;
2261 }
2262 if (ses->capabilities & CAP_STATUS32) {
2263 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2264 capabilities |= CAP_STATUS32;
2265 }
2266 if (ses->capabilities & CAP_DFS) {
2267 smb_buffer->Flags2 |= SMBFLG2_DFS;
2268 capabilities |= CAP_DFS;
2269 }
2270 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2271
Steve French50c2f752007-07-13 00:33:32 +00002272 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002273 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274
2275 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002276 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002278 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2279 bcc_ptr += CIFS_SESS_KEY_SIZE;
2280 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2281 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
2283 if (ses->capabilities & CAP_UNICODE) {
2284 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2285 *bcc_ptr = 0;
2286 bcc_ptr++;
2287 }
Steve French4523cc32007-04-30 20:13:06 +00002288 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002289 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002290 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002292 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 nls_codepage);
2294 /* convert number of 16 bit words to bytes */
2295 bcc_ptr += 2 * bytes_returned;
2296 bcc_ptr += 2; /* trailing null */
2297 if (domain == NULL)
2298 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002299 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 "CIFS_LINUX_DOM", 32, nls_codepage);
2301 else
2302 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002303 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 nls_codepage);
2305 bcc_ptr += 2 * bytes_returned;
2306 bcc_ptr += 2;
2307 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002308 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 32, nls_codepage);
2310 bcc_ptr += 2 * bytes_returned;
2311 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002312 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 32, nls_codepage);
2314 bcc_ptr += 2 * bytes_returned;
2315 bcc_ptr += 2;
2316 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002317 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 64, nls_codepage);
2319 bcc_ptr += 2 * bytes_returned;
2320 bcc_ptr += 2;
2321 } else {
Steve French50c2f752007-07-13 00:33:32 +00002322 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 strncpy(bcc_ptr, user, 200);
2324 bcc_ptr += strnlen(user, 200);
2325 }
2326 *bcc_ptr = 0;
2327 bcc_ptr++;
2328 if (domain == NULL) {
2329 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2330 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2331 } else {
2332 strncpy(bcc_ptr, domain, 64);
2333 bcc_ptr += strnlen(domain, 64);
2334 *bcc_ptr = 0;
2335 bcc_ptr++;
2336 }
2337 strcpy(bcc_ptr, "Linux version ");
2338 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002339 strcpy(bcc_ptr, utsname()->release);
2340 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2342 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2343 }
2344 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2345 smb_buffer->smb_buf_length += count;
2346 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2347
2348 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002349 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 if (rc) {
2351/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2352 } else if ((smb_buffer_response->WordCount == 3)
2353 || (smb_buffer_response->WordCount == 4)) {
2354 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2355 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2356 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002357 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2358 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2359 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002361 /* response can have either 3 or 4 word count - Samba sends 3 */
2362 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 if ((pSMBr->resp.hdr.WordCount == 3)
2364 || ((pSMBr->resp.hdr.WordCount == 4)
2365 && (blob_len < pSMBr->resp.ByteCount))) {
2366 if (pSMBr->resp.hdr.WordCount == 4)
2367 bcc_ptr += blob_len;
2368
2369 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2370 if ((long) (bcc_ptr) % 2) {
2371 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002372 (BCC(smb_buffer_response) - 1) / 2;
2373 /* Unicode strings must be word
2374 aligned */
2375 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 } else {
2377 remaining_words =
2378 BCC(smb_buffer_response) / 2;
2379 }
2380 len =
2381 UniStrnlen((wchar_t *) bcc_ptr,
2382 remaining_words - 1);
2383/* We look for obvious messed up bcc or strings in response so we do not go off
2384 the end since (at least) WIN2K and Windows XP have a major bug in not null
2385 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002386 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002387 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002388 ses->serverOS = kzalloc(2 * (len + 1),
2389 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002390 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002391 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002393 (__le16 *)bcc_ptr,
2394 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 bcc_ptr += 2 * (len + 1);
2396 remaining_words -= len + 1;
2397 ses->serverOS[2 * len] = 0;
2398 ses->serverOS[1 + (2 * len)] = 0;
2399 if (remaining_words > 0) {
2400 len = UniStrnlen((wchar_t *)bcc_ptr,
2401 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002402 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002403 ses->serverNOS = kzalloc(2 * (len + 1),
2404 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002405 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002406 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002408 (__le16 *)bcc_ptr,
2409 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 bcc_ptr += 2 * (len + 1);
2411 ses->serverNOS[2 * len] = 0;
2412 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002413 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002414 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002415 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 ses->flags |= CIFS_SES_NT4;
2417 }
2418 remaining_words -= len + 1;
2419 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002420 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002421 /* last string is not always null terminated
2422 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002423 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002424 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002426 kzalloc(2*(len+1),
2427 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002428 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002429 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002431 (__le16 *)bcc_ptr,
2432 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 bcc_ptr += 2 * (len + 1);
2434 ses->serverDomain[2*len] = 0;
2435 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002436 } else { /* else no more room so create
2437 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002438 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002439 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002440 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002441 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002442 }
Steve French50c2f752007-07-13 00:33:32 +00002443 } else { /* no room so create dummy domain
2444 and NOS string */
2445
Steve French433dc242005-04-28 22:41:08 -07002446 /* if these kcallocs fail not much we
2447 can do, but better to not fail the
2448 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002449 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002451 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002452 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002454 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 }
2456 } else { /* ASCII */
2457 len = strnlen(bcc_ptr, 1024);
2458 if (((long) bcc_ptr + len) - (long)
2459 pByteArea(smb_buffer_response)
2460 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002461 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002462 ses->serverOS = kzalloc(len + 1,
2463 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002464 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002465 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002466 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
2468 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002469 /* null terminate the string */
2470 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 bcc_ptr++;
2472
2473 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002474 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002475 ses->serverNOS = kzalloc(len + 1,
2476 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002477 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002478 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 strncpy(ses->serverNOS, bcc_ptr, len);
2480 bcc_ptr += len;
2481 bcc_ptr[0] = 0;
2482 bcc_ptr++;
2483
2484 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002485 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002486 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002487 ses->serverDomain = kzalloc(len + 1,
2488 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002489 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002490 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002491 strncpy(ses->serverDomain, bcc_ptr,
2492 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 bcc_ptr += len;
2494 bcc_ptr[0] = 0;
2495 bcc_ptr++;
2496 } else
2497 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002498 ("Variable field of length %d "
2499 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 len));
2501 }
2502 } else {
2503 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002504 (" Security Blob Length extends beyond "
2505 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 }
2507 } else {
2508 cERROR(1,
2509 (" Invalid Word count %d: ",
2510 smb_buffer_response->WordCount));
2511 rc = -EIO;
2512 }
Steve French433dc242005-04-28 22:41:08 -07002513sesssetup_nomem: /* do not return an error on nomem for the info strings,
2514 since that could make reconnection harder, and
2515 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002516 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517
2518 return rc;
2519}
2520
2521static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002523 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 const struct nls_table *nls_codepage)
2525{
2526 struct smb_hdr *smb_buffer;
2527 struct smb_hdr *smb_buffer_response;
2528 SESSION_SETUP_ANDX *pSMB;
2529 SESSION_SETUP_ANDX *pSMBr;
2530 char *bcc_ptr;
2531 char *domain;
2532 int rc = 0;
2533 int remaining_words = 0;
2534 int bytes_returned = 0;
2535 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002536 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 PNEGOTIATE_MESSAGE SecurityBlob;
2538 PCHALLENGE_MESSAGE SecurityBlob2;
2539 __u32 negotiate_flags, capabilities;
2540 __u16 count;
2541
Steve French12b3b8f2006-02-09 21:12:47 +00002542 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002543 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 return -EINVAL;
2545 domain = ses->domainName;
2546 *pNTLMv2_flag = FALSE;
2547 smb_buffer = cifs_buf_get();
2548 if (smb_buffer == NULL) {
2549 return -ENOMEM;
2550 }
2551 smb_buffer_response = smb_buffer;
2552 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2553 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2554
2555 /* send SMBsessionSetup here */
2556 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2557 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002558
2559 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2561 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2562
2563 pSMB->req.AndXCommand = 0xFF;
2564 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2565 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2566
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002567 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2569
2570 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2571 CAP_EXTENDED_SECURITY;
2572 if (ses->capabilities & CAP_UNICODE) {
2573 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2574 capabilities |= CAP_UNICODE;
2575 }
2576 if (ses->capabilities & CAP_STATUS32) {
2577 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2578 capabilities |= CAP_STATUS32;
2579 }
2580 if (ses->capabilities & CAP_DFS) {
2581 smb_buffer->Flags2 |= SMBFLG2_DFS;
2582 capabilities |= CAP_DFS;
2583 }
2584 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2585
2586 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2587 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2588 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2589 SecurityBlob->MessageType = NtLmNegotiate;
2590 negotiate_flags =
2591 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002592 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2593 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002595 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002597/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002598 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 /* setup pointers to domain name and workstation name */
2600 bcc_ptr += SecurityBlobLength;
2601
2602 SecurityBlob->WorkstationName.Buffer = 0;
2603 SecurityBlob->WorkstationName.Length = 0;
2604 SecurityBlob->WorkstationName.MaximumLength = 0;
2605
Steve French12b3b8f2006-02-09 21:12:47 +00002606 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2607 along with username on auth request (ie the response to challenge) */
2608 SecurityBlob->DomainName.Buffer = 0;
2609 SecurityBlob->DomainName.Length = 0;
2610 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 if (ses->capabilities & CAP_UNICODE) {
2612 if ((long) bcc_ptr % 2) {
2613 *bcc_ptr = 0;
2614 bcc_ptr++;
2615 }
2616
2617 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002618 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 32, nls_codepage);
2620 bcc_ptr += 2 * bytes_returned;
2621 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002622 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 nls_codepage);
2624 bcc_ptr += 2 * bytes_returned;
2625 bcc_ptr += 2; /* null terminate Linux version */
2626 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002627 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 64, nls_codepage);
2629 bcc_ptr += 2 * bytes_returned;
2630 *(bcc_ptr + 1) = 0;
2631 *(bcc_ptr + 2) = 0;
2632 bcc_ptr += 2; /* null terminate network opsys string */
2633 *(bcc_ptr + 1) = 0;
2634 *(bcc_ptr + 2) = 0;
2635 bcc_ptr += 2; /* null domain */
2636 } else { /* ASCII */
2637 strcpy(bcc_ptr, "Linux version ");
2638 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002639 strcpy(bcc_ptr, utsname()->release);
2640 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2642 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2643 bcc_ptr++; /* empty domain field */
2644 *bcc_ptr = 0;
2645 }
2646 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2647 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2648 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2649 smb_buffer->smb_buf_length += count;
2650 pSMB->req.ByteCount = cpu_to_le16(count);
2651
2652 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002653 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655 if (smb_buffer_response->Status.CifsError ==
2656 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2657 rc = 0;
2658
2659 if (rc) {
2660/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2661 } else if ((smb_buffer_response->WordCount == 3)
2662 || (smb_buffer_response->WordCount == 4)) {
2663 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2664 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2665
2666 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002667 cFYI(1, (" Guest login"));
2668 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
Steve French50c2f752007-07-13 00:33:32 +00002670 bcc_ptr = pByteArea(smb_buffer_response);
2671 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2674 if (SecurityBlob2->MessageType != NtLmChallenge) {
2675 cFYI(1,
2676 ("Unexpected NTLMSSP message type received %d",
2677 SecurityBlob2->MessageType));
2678 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002679 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002680 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 if ((pSMBr->resp.hdr.WordCount == 3)
2682 || ((pSMBr->resp.hdr.WordCount == 4)
2683 && (blob_len <
2684 pSMBr->resp.ByteCount))) {
2685
2686 if (pSMBr->resp.hdr.WordCount == 4) {
2687 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002688 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 blob_len));
2690 }
2691
Steve French12b3b8f2006-02-09 21:12:47 +00002692 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
2694 memcpy(ses->server->cryptKey,
2695 SecurityBlob2->Challenge,
2696 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002697 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002698 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 *pNTLMv2_flag = TRUE;
2700
Steve French50c2f752007-07-13 00:33:32 +00002701 if ((SecurityBlob2->NegotiateFlags &
2702 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002704 ses->server->secMode |=
2705 SECMODE_SIGN_REQUIRED;
2706 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002708 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 SECMODE_SIGN_ENABLED;
2710
2711 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2712 if ((long) (bcc_ptr) % 2) {
2713 remaining_words =
2714 (BCC(smb_buffer_response)
2715 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002716 /* Must word align unicode strings */
2717 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 } else {
2719 remaining_words =
2720 BCC
2721 (smb_buffer_response) / 2;
2722 }
2723 len =
2724 UniStrnlen((wchar_t *) bcc_ptr,
2725 remaining_words - 1);
2726/* We look for obvious messed up bcc or strings in response so we do not go off
2727 the end since (at least) WIN2K and Windows XP have a major bug in not null
2728 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002729 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002730 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002732 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002734 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 bcc_ptr, len,
2736 nls_codepage);
2737 bcc_ptr += 2 * (len + 1);
2738 remaining_words -= len + 1;
2739 ses->serverOS[2 * len] = 0;
2740 ses->serverOS[1 + (2 * len)] = 0;
2741 if (remaining_words > 0) {
2742 len = UniStrnlen((wchar_t *)
2743 bcc_ptr,
2744 remaining_words
2745 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002746 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002748 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 GFP_KERNEL);
2750 cifs_strfromUCS_le(ses->
2751 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002752 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 bcc_ptr,
2754 len,
2755 nls_codepage);
2756 bcc_ptr += 2 * (len + 1);
2757 ses->serverNOS[2 * len] = 0;
2758 ses->serverNOS[1 +
2759 (2 * len)] = 0;
2760 remaining_words -= len + 1;
2761 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002762 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2763 /* last string not always null terminated
2764 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002765 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002767 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 (len +
2769 1),
2770 GFP_KERNEL);
2771 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002772 (ses->serverDomain,
2773 (__le16 *)bcc_ptr,
2774 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 bcc_ptr +=
2776 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002777 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002779 ses->serverDomain
2780 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 = 0;
2782 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002783 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002784 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002786 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002790 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002792 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002793 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002795 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 }
2797 } else { /* ASCII */
2798 len = strnlen(bcc_ptr, 1024);
2799 if (((long) bcc_ptr + len) - (long)
2800 pByteArea(smb_buffer_response)
2801 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002802 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002803 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002805 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 GFP_KERNEL);
2807 strncpy(ses->serverOS,
2808 bcc_ptr, len);
2809
2810 bcc_ptr += len;
2811 bcc_ptr[0] = 0; /* null terminate string */
2812 bcc_ptr++;
2813
2814 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002815 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002817 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 GFP_KERNEL);
2819 strncpy(ses->serverNOS, bcc_ptr, len);
2820 bcc_ptr += len;
2821 bcc_ptr[0] = 0;
2822 bcc_ptr++;
2823
2824 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002825 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002827 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002829 strncpy(ses->serverDomain,
2830 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 bcc_ptr += len;
2832 bcc_ptr[0] = 0;
2833 bcc_ptr++;
2834 } else
2835 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002836 ("field of length %d "
2837 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 len));
2839 }
2840 } else {
Steve French50c2f752007-07-13 00:33:32 +00002841 cERROR(1, ("Security Blob Length extends beyond"
2842 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 }
2844 } else {
2845 cERROR(1, ("No session structure passed in."));
2846 }
2847 } else {
2848 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002849 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 smb_buffer_response->WordCount));
2851 rc = -EIO;
2852 }
2853
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002854 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855
2856 return rc;
2857}
2858static int
2859CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002860 char *ntlm_session_key, int ntlmv2_flag,
2861 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862{
2863 struct smb_hdr *smb_buffer;
2864 struct smb_hdr *smb_buffer_response;
2865 SESSION_SETUP_ANDX *pSMB;
2866 SESSION_SETUP_ANDX *pSMBr;
2867 char *bcc_ptr;
2868 char *user;
2869 char *domain;
2870 int rc = 0;
2871 int remaining_words = 0;
2872 int bytes_returned = 0;
2873 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002874 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 PAUTHENTICATE_MESSAGE SecurityBlob;
2876 __u32 negotiate_flags, capabilities;
2877 __u16 count;
2878
2879 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002880 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 return -EINVAL;
2882 user = ses->userName;
2883 domain = ses->domainName;
2884 smb_buffer = cifs_buf_get();
2885 if (smb_buffer == NULL) {
2886 return -ENOMEM;
2887 }
2888 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002889 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
2890 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891
2892 /* send SMBsessionSetup here */
2893 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2894 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002895
2896 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2898 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2899 pSMB->req.AndXCommand = 0xFF;
2900 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2901 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2902
2903 pSMB->req.hdr.Uid = ses->Suid;
2904
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002905 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2907
2908 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002909 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 if (ses->capabilities & CAP_UNICODE) {
2911 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2912 capabilities |= CAP_UNICODE;
2913 }
2914 if (ses->capabilities & CAP_STATUS32) {
2915 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2916 capabilities |= CAP_STATUS32;
2917 }
2918 if (ses->capabilities & CAP_DFS) {
2919 smb_buffer->Flags2 |= SMBFLG2_DFS;
2920 capabilities |= CAP_DFS;
2921 }
2922 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2923
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002924 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
2925 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2927 SecurityBlob->MessageType = NtLmAuthenticate;
2928 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002929 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2930 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2931 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002932 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002934 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2936
2937/* setup pointers to domain name and workstation name */
2938
2939 SecurityBlob->WorkstationName.Buffer = 0;
2940 SecurityBlob->WorkstationName.Length = 0;
2941 SecurityBlob->WorkstationName.MaximumLength = 0;
2942 SecurityBlob->SessionKey.Length = 0;
2943 SecurityBlob->SessionKey.MaximumLength = 0;
2944 SecurityBlob->SessionKey.Buffer = 0;
2945
2946 SecurityBlob->LmChallengeResponse.Length = 0;
2947 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2948 SecurityBlob->LmChallengeResponse.Buffer = 0;
2949
2950 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002951 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002953 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2954 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 SecurityBlob->NtChallengeResponse.Buffer =
2956 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002957 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2958 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960 if (ses->capabilities & CAP_UNICODE) {
2961 if (domain == NULL) {
2962 SecurityBlob->DomainName.Buffer = 0;
2963 SecurityBlob->DomainName.Length = 0;
2964 SecurityBlob->DomainName.MaximumLength = 0;
2965 } else {
Steve French77159b42007-08-31 01:10:17 +00002966 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00002968 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00002970 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 SecurityBlob->DomainName.Buffer =
2972 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00002973 bcc_ptr += ln;
2974 SecurityBlobLength += ln;
2975 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 }
2977 if (user == NULL) {
2978 SecurityBlob->UserName.Buffer = 0;
2979 SecurityBlob->UserName.Length = 0;
2980 SecurityBlob->UserName.MaximumLength = 0;
2981 } else {
Steve French77159b42007-08-31 01:10:17 +00002982 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00002984 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00002986 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 SecurityBlob->UserName.Buffer =
2988 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00002989 bcc_ptr += ln;
2990 SecurityBlobLength += ln;
2991 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 }
2993
Steve French63135e02007-07-17 17:34:02 +00002994 /* SecurityBlob->WorkstationName.Length =
2995 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00002997 SecurityBlob->WorkstationName.MaximumLength =
2998 cpu_to_le16(SecurityBlob->WorkstationName.Length);
2999 SecurityBlob->WorkstationName.Buffer =
3000 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 bcc_ptr += SecurityBlob->WorkstationName.Length;
3002 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003003 SecurityBlob->WorkstationName.Length =
3004 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
3006 if ((long) bcc_ptr % 2) {
3007 *bcc_ptr = 0;
3008 bcc_ptr++;
3009 }
3010 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003011 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 32, nls_codepage);
3013 bcc_ptr += 2 * bytes_returned;
3014 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003015 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 nls_codepage);
3017 bcc_ptr += 2 * bytes_returned;
3018 bcc_ptr += 2; /* null term version string */
3019 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003020 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 64, nls_codepage);
3022 bcc_ptr += 2 * bytes_returned;
3023 *(bcc_ptr + 1) = 0;
3024 *(bcc_ptr + 2) = 0;
3025 bcc_ptr += 2; /* null terminate network opsys string */
3026 *(bcc_ptr + 1) = 0;
3027 *(bcc_ptr + 2) = 0;
3028 bcc_ptr += 2; /* null domain */
3029 } else { /* ASCII */
3030 if (domain == NULL) {
3031 SecurityBlob->DomainName.Buffer = 0;
3032 SecurityBlob->DomainName.Length = 0;
3033 SecurityBlob->DomainName.MaximumLength = 0;
3034 } else {
Steve French77159b42007-08-31 01:10:17 +00003035 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3037 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003038 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003040 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 SecurityBlob->DomainName.Buffer =
3042 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003043 bcc_ptr += ln;
3044 SecurityBlobLength += ln;
3045 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 }
3047 if (user == NULL) {
3048 SecurityBlob->UserName.Buffer = 0;
3049 SecurityBlob->UserName.Length = 0;
3050 SecurityBlob->UserName.MaximumLength = 0;
3051 } else {
Steve French77159b42007-08-31 01:10:17 +00003052 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003054 ln = strnlen(user, 64);
3055 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003057 cpu_to_le32(SecurityBlobLength);
3058 bcc_ptr += ln;
3059 SecurityBlobLength += ln;
3060 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 }
3062 /* BB fill in our workstation name if known BB */
3063
3064 strcpy(bcc_ptr, "Linux version ");
3065 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003066 strcpy(bcc_ptr, utsname()->release);
3067 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3069 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3070 bcc_ptr++; /* null domain */
3071 *bcc_ptr = 0;
3072 }
3073 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3074 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3075 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3076 smb_buffer->smb_buf_length += count;
3077 pSMB->req.ByteCount = cpu_to_le16(count);
3078
3079 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003080 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003082/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3083 } else if ((smb_buffer_response->WordCount == 3) ||
3084 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003086 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003088 cFYI(1, (" Guest login")); /* BB Should we set anything
3089 in SesInfo struct ? */
3090/* if (SecurityBlob2->MessageType != NtLm??) {
3091 cFYI("Unexpected message type on auth response is %d"));
3092 } */
3093
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 if (ses) {
3095 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003096 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003098 /* UID left in wire format */
3099 ses->Suid = smb_buffer_response->Uid;
3100 bcc_ptr = pByteArea(smb_buffer_response);
3101 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 if ((pSMBr->resp.hdr.WordCount == 3)
3103 || ((pSMBr->resp.hdr.WordCount == 4)
3104 && (blob_len <
3105 pSMBr->resp.ByteCount))) {
3106 if (pSMBr->resp.hdr.WordCount == 4) {
3107 bcc_ptr +=
3108 blob_len;
3109 cFYI(1,
3110 ("Security Blob Length %d ",
3111 blob_len));
3112 }
3113
3114 cFYI(1,
3115 ("NTLMSSP response to Authenticate "));
3116
3117 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3118 if ((long) (bcc_ptr) % 2) {
3119 remaining_words =
3120 (BCC(smb_buffer_response)
3121 - 1) / 2;
3122 bcc_ptr++; /* Unicode strings must be word aligned */
3123 } else {
3124 remaining_words = BCC(smb_buffer_response) / 2;
3125 }
Steve French77159b42007-08-31 01:10:17 +00003126 len = UniStrnlen((wchar_t *) bcc_ptr,
3127 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128/* We look for obvious messed up bcc or strings in response so we do not go off
3129 the end since (at least) WIN2K and Windows XP have a major bug in not null
3130 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003131 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003132 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003134 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003136 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 bcc_ptr, len,
3138 nls_codepage);
3139 bcc_ptr += 2 * (len + 1);
3140 remaining_words -= len + 1;
3141 ses->serverOS[2 * len] = 0;
3142 ses->serverOS[1 + (2 * len)] = 0;
3143 if (remaining_words > 0) {
3144 len = UniStrnlen((wchar_t *)
3145 bcc_ptr,
3146 remaining_words
3147 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003148 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003150 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 GFP_KERNEL);
3152 cifs_strfromUCS_le(ses->
3153 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003154 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 bcc_ptr,
3156 len,
3157 nls_codepage);
3158 bcc_ptr += 2 * (len + 1);
3159 ses->serverNOS[2 * len] = 0;
3160 ses->serverNOS[1+(2*len)] = 0;
3161 remaining_words -= len + 1;
3162 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003163 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003165 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003166 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003168 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 (len +
3170 1),
3171 GFP_KERNEL);
3172 cifs_strfromUCS_le
3173 (ses->
3174 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003175 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 bcc_ptr, len,
3177 nls_codepage);
3178 bcc_ptr +=
3179 2 * (len + 1);
3180 ses->
3181 serverDomain[2
3182 * len]
3183 = 0;
3184 ses->
3185 serverDomain[1
3186 +
3187 (2
3188 *
3189 len)]
3190 = 0;
3191 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003192 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003193 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003194 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003195 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003198 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003199 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003200 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003201 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003202 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 }
3204 } else { /* ASCII */
3205 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003206 if (((long) bcc_ptr + len) -
3207 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003208 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003209 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003210 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003211 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 strncpy(ses->serverOS,bcc_ptr, len);
3213
3214 bcc_ptr += len;
3215 bcc_ptr[0] = 0; /* null terminate the string */
3216 bcc_ptr++;
3217
3218 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003219 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003220 ses->serverNOS = kzalloc(len+1,
3221 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003222 strncpy(ses->serverNOS,
3223 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 bcc_ptr += len;
3225 bcc_ptr[0] = 0;
3226 bcc_ptr++;
3227
3228 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003229 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003230 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003231 ses->serverDomain =
3232 kzalloc(len+1,
3233 GFP_KERNEL);
3234 strncpy(ses->serverDomain,
3235 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 bcc_ptr += len;
3237 bcc_ptr[0] = 0;
3238 bcc_ptr++;
3239 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003240 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003241 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 len));
3243 }
3244 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003245 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003246 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 }
3248 } else {
3249 cERROR(1, ("No session structure passed in."));
3250 }
3251 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003252 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 smb_buffer_response->WordCount));
3254 rc = -EIO;
3255 }
3256
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003257 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
3259 return rc;
3260}
3261
3262int
3263CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3264 const char *tree, struct cifsTconInfo *tcon,
3265 const struct nls_table *nls_codepage)
3266{
3267 struct smb_hdr *smb_buffer;
3268 struct smb_hdr *smb_buffer_response;
3269 TCONX_REQ *pSMB;
3270 TCONX_RSP *pSMBr;
3271 unsigned char *bcc_ptr;
3272 int rc = 0;
3273 int length;
3274 __u16 count;
3275
3276 if (ses == NULL)
3277 return -EIO;
3278
3279 smb_buffer = cifs_buf_get();
3280 if (smb_buffer == NULL) {
3281 return -ENOMEM;
3282 }
3283 smb_buffer_response = smb_buffer;
3284
3285 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3286 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003287
3288 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 smb_buffer->Uid = ses->Suid;
3290 pSMB = (TCONX_REQ *) smb_buffer;
3291 pSMBr = (TCONX_RSP *) smb_buffer_response;
3292
3293 pSMB->AndXCommand = 0xFF;
3294 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003296 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003297 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003298 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003299 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003300 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003301 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003302 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003303 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3304 specified as required (when that support is added to
3305 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003306 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003307 by Samba (not sure whether other servers allow
3308 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003309#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003310 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003311 (ses->server->secType == LANMAN))
3312 calc_lanman_hash(ses, bcc_ptr);
3313 else
3314#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003315 SMBNTencrypt(ses->password,
3316 ses->server->cryptKey,
3317 bcc_ptr);
3318
Steve French7c7b25b2006-06-01 19:20:10 +00003319 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003320 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003321 /* must align unicode strings */
3322 *bcc_ptr = 0; /* null byte password */
3323 bcc_ptr++;
3324 }
Steve Frencheeac8042006-01-13 21:34:58 -08003325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326
Steve French50c2f752007-07-13 00:33:32 +00003327 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003328 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3330
3331 if (ses->capabilities & CAP_STATUS32) {
3332 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3333 }
3334 if (ses->capabilities & CAP_DFS) {
3335 smb_buffer->Flags2 |= SMBFLG2_DFS;
3336 }
3337 if (ses->capabilities & CAP_UNICODE) {
3338 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3339 length =
Steve French50c2f752007-07-13 00:33:32 +00003340 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3341 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003342 (/* server len*/ + 256 /* share len */), nls_codepage);
3343 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 bcc_ptr += 2; /* skip trailing null */
3345 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 strcpy(bcc_ptr, tree);
3347 bcc_ptr += strlen(tree) + 1;
3348 }
3349 strcpy(bcc_ptr, "?????");
3350 bcc_ptr += strlen("?????");
3351 bcc_ptr += 1;
3352 count = bcc_ptr - &pSMB->Password[0];
3353 pSMB->hdr.smb_buf_length += count;
3354 pSMB->ByteCount = cpu_to_le16(count);
3355
Steve French133672e2007-11-13 22:41:37 +00003356 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3357 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358
3359 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3360 /* above now done in SendReceive */
3361 if ((rc == 0) && (tcon != NULL)) {
3362 tcon->tidStatus = CifsGood;
3363 tcon->tid = smb_buffer_response->Tid;
3364 bcc_ptr = pByteArea(smb_buffer_response);
3365 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003366 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003367 if (length == 3) {
3368 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3369 (bcc_ptr[2] == 'C')) {
3370 cFYI(1, ("IPC connection"));
3371 tcon->ipc = 1;
3372 }
3373 } else if (length == 2) {
3374 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3375 /* the most common case */
3376 cFYI(1, ("disk share connection"));
3377 }
3378 }
Steve French50c2f752007-07-13 00:33:32 +00003379 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3381 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3382 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3383 if ((bcc_ptr + (2 * length)) -
3384 pByteArea(smb_buffer_response) <=
3385 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003386 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003388 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003389 if (tcon->nativeFileSystem)
3390 cifs_strfromUCS_le(
3391 tcon->nativeFileSystem,
3392 (__le16 *) bcc_ptr,
3393 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 bcc_ptr += 2 * length;
3395 bcc_ptr[0] = 0; /* null terminate the string */
3396 bcc_ptr[1] = 0;
3397 bcc_ptr += 2;
3398 }
Steve French50c2f752007-07-13 00:33:32 +00003399 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 } else {
3401 length = strnlen(bcc_ptr, 1024);
3402 if ((bcc_ptr + length) -
3403 pByteArea(smb_buffer_response) <=
3404 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003405 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003407 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003408 if (tcon->nativeFileSystem)
3409 strncpy(tcon->nativeFileSystem, bcc_ptr,
3410 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 }
Steve French50c2f752007-07-13 00:33:32 +00003412 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003414 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003415 (smb_buffer_response->WordCount == 7))
3416 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003417 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3418 else
3419 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3421 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003422 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 ses->ipc_tid = smb_buffer_response->Tid;
3424 }
3425
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003426 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 return rc;
3428}
3429
3430int
3431cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3432{
3433 int rc = 0;
3434 int xid;
3435 struct cifsSesInfo *ses = NULL;
3436 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003437 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438
3439 xid = GetXid();
3440
3441 if (cifs_sb->tcon) {
3442 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3443 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3444 if (rc == -EBUSY) {
3445 FreeXid(xid);
3446 return 0;
3447 }
3448 tconInfoFree(cifs_sb->tcon);
3449 if ((ses) && (ses->server)) {
3450 /* save off task so we do not refer to ses later */
3451 cifsd_task = ses->server->tsk;
3452 cFYI(1, ("About to do SMBLogoff "));
3453 rc = CIFSSMBLogoff(xid, ses);
3454 if (rc == -EBUSY) {
3455 FreeXid(xid);
3456 return 0;
3457 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003458 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003459 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003460 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003461 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 rc = 0;
3464 } /* else - we have an smb session
3465 left on this socket do not kill cifsd */
3466 } else
3467 cFYI(1, ("No session or bad tcon"));
3468 }
Steve French50c2f752007-07-13 00:33:32 +00003469
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003471 tmp = cifs_sb->prepath;
3472 cifs_sb->prepathlen = 0;
3473 cifs_sb->prepath = NULL;
3474 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003475 if (ses)
3476 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 if (ses)
3478 sesInfoFree(ses);
3479
3480 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003481 return rc; /* BB check if we should always return zero here */
3482}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483
3484int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003485 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486{
3487 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003488 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003490 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
3492 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003493 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003495 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003497 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 rc = -EHOSTDOWN;
3499 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003500 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003502 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 pSesInfo->server->tcpStatus = CifsGood;
3504 else
3505 rc = -EHOSTDOWN;
3506 spin_unlock(&GlobalMid_Lock);
3507
3508 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003509 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 }
3511 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003512 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003514 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003516 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003517 cFYI(1,
3518 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 pSesInfo->server->secMode,
3520 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003521 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003522 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003523 rc = CIFS_SessSetup(xid, pSesInfo,
3524 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003525 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003526 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003527 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003529 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 } else if (extended_security
3531 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3532 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003533 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3535 pSesInfo,
3536 &ntlmv2_flag,
3537 nls_info);
3538 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003539 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003540 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003541 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003542 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 nls_info)) {
3544 rc = -ENOMEM;
3545 goto ss_err_exit;
3546 } else
3547 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003548 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003549 CalcNTLMv2_response(pSesInfo,
3550 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003551 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003552 cifs_calculate_ntlmv2_mac_key(
3553 pSesInfo->server->mac_signing_key,
3554 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 kfree(v2_response);
3556 /* BB Put dummy sig in SessSetup PDU? */
3557 } else {
3558 rc = -ENOMEM;
3559 goto ss_err_exit;
3560 }
3561
3562 } else {
3563 SMBNTencrypt(pSesInfo->password,
3564 pSesInfo->server->cryptKey,
3565 ntlm_session_key);
3566
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003567 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003568 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003569 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003570 ntlm_session_key,
3571 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 }
3573 /* for better security the weaker lanman hash not sent
3574 in AuthSessSetup so we no longer calculate it */
3575
3576 rc = CIFSNTLMSSPAuthSessSetup(xid,
3577 pSesInfo,
3578 ntlm_session_key,
3579 ntlmv2_flag,
3580 nls_info);
3581 }
3582 } else { /* old style NTLM 0.12 session setup */
3583 SMBNTencrypt(pSesInfo->password,
3584 pSesInfo->server->cryptKey,
3585 ntlm_session_key);
3586
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003587 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003588 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003589 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003590 ntlm_session_key, pSesInfo->password);
3591
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 rc = CIFSSessSetup(xid, pSesInfo,
3593 ntlm_session_key, nls_info);
3594 }
3595 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003596 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 } else {
Steve French467a8f82007-06-27 22:41:32 +00003598 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 pSesInfo->status = CifsGood;
3600 }
3601 }
3602ss_err_exit:
3603 return rc;
3604}
3605