blob: 21cac15ed9a720fe607d661e5ef26fb42ca28019 [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));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000163 server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);
164 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 */
354 cFYI(1, ("Demultiplex PID: %d", current->pid));
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 */
418 continue;
419 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000420 if (server->tcpStatus == CifsNew) {
421 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700422 /* some servers kill the TCP session rather than
423 returning an SMB negprot error, in which
424 case reconnecting here is not going to help,
425 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000428 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000429 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 break;
431 }
Steve French467a8f82007-06-27 22:41:32 +0000432 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700433 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 cifs_reconnect(server);
435 csocket = server->ssocket;
436 wake_up(&server->response_q);
437 continue;
Steve French46810cb2005-04-28 22:41:09 -0700438 } else if (length < 4) {
Steve Frenchf01d5e12007-08-30 21:13:31 +0000439 cFYI(1, ("less than four bytes received (%d bytes)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000441 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000442 msleep(1);
443 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 }
Steve French67010fb2005-04-28 22:41:09 -0700445
Steve French70ca7342005-09-22 16:32:06 -0700446 /* The right amount was read from socket - 4 bytes */
447 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700448
Steve French70ca7342005-09-22 16:32:06 -0700449 /* the first byte big endian of the length field,
450 is actually not part of the length but the type
451 with the most common, zero, as regular data */
452 temp = *((char *) smb_buffer);
453
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000454 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700455 but we convert it here so it is always manipulated
456 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700457 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700458 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700459
Steve French467a8f82007-06-27 22:41:32 +0000460 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700461
462 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 continue;
Steve French70ca7342005-09-22 16:32:06 -0700464 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000465 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700466 continue;
Steve French70ca7342005-09-22 16:32:06 -0700467 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000468 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700469 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000470 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700471 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000472 if (server->tcpStatus == CifsNew) {
473 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700474 ret of smb negprot error) reconnecting
475 not going to help, ret error to mount */
476 break;
477 } else {
478 /* give server a second to
479 clean up before reconnect attempt */
480 msleep(1000);
481 /* always try 445 first on reconnect
482 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000483 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700484 since we do not begin with RFC1001
485 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000486 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700487 htons(CIFS_PORT);
488 cifs_reconnect(server);
489 csocket = server->ssocket;
490 wake_up(&server->response_q);
491 continue;
492 }
Steve French70ca7342005-09-22 16:32:06 -0700493 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000494 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700495 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
496 length);
Steve French46810cb2005-04-28 22:41:09 -0700497 cifs_reconnect(server);
498 csocket = server->ssocket;
499 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700500 }
501
502 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000503 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000504 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700506 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700507 cifs_reconnect(server);
508 csocket = server->ssocket;
509 wake_up(&server->response_q);
510 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000511 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700512
513 /* else length ok */
514 reconnect = 0;
515
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000516 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700517 isLargeBuf = TRUE;
518 memcpy(bigbuf, smallbuf, 4);
519 smb_buffer = bigbuf;
520 }
521 length = 0;
522 iov.iov_base = 4 + (char *)smb_buffer;
523 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000524 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700525 total_read += length) {
526 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
527 pdu_length - total_read, 0);
Steve French26f57362007-08-30 22:09:15 +0000528 if (kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700529 (length == -EINTR)) {
530 /* then will exit */
531 reconnect = 2;
532 break;
533 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700534 cifs_reconnect(server);
535 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000536 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700537 /* Now we will reread sock */
538 reconnect = 1;
539 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 (length == -EAGAIN)) {
542 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000543 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700544 threads to set tcpStatus
545 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700546 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000548 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700549 pdu_length - total_read));
550 cifs_reconnect(server);
551 csocket = server->ssocket;
552 reconnect = 1;
553 break;
Steve French46810cb2005-04-28 22:41:09 -0700554 }
555 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000556 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700557 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000558 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700559 continue;
560
561 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000562
Steve Frenche4eb2952005-04-28 22:41:09 -0700563
564 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000565 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700566 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700567 continue;
568 }
569
570
571 task_to_wake = NULL;
572 spin_lock(&GlobalMid_Lock);
573 list_for_each(tmp, &server->pending_mid_q) {
574 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
575
Steve French50c2f752007-07-13 00:33:32 +0000576 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700577 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
578 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000579 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700581 isMultiRsp = TRUE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000582 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000584 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700585 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000586 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 break;
588 } else {
589 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000590 mid_entry->multiEnd = 1;
Steve French50c2f752007-07-13 00:33:32 +0000591 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700592 }
593 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000594 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 cERROR(1,("1st trans2 resp needs bigbuf"));
596 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000597 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700599 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700600 mid_entry->resp_buf =
601 smb_buffer;
602 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 bigbuf = NULL;
604 }
605 }
606 break;
Steve French50c2f752007-07-13 00:33:32 +0000607 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700608 mid_entry->resp_buf = smb_buffer;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000609 if (isLargeBuf)
Steve Frenche4eb2952005-04-28 22:41:09 -0700610 mid_entry->largeBuf = 1;
611 else
612 mid_entry->largeBuf = 0;
613multi_t2_fnd:
614 task_to_wake = mid_entry->tsk;
615 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700616#ifdef CONFIG_CIFS_STATS2
617 mid_entry->when_received = jiffies;
618#endif
Steve French3a5ff612006-07-14 22:37:11 +0000619 /* so we do not time out requests to server
620 which is still responding (since server could
621 be busy but not dead) */
622 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700623 break;
624 }
625 }
626 spin_unlock(&GlobalMid_Lock);
627 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700628 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000629 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700630 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000631 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700632 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000633 else
Steve Frenchcd634992005-04-28 22:41:10 -0700634 smallbuf = NULL;
635 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700636 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000637 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve French50c2f752007-07-13 00:33:32 +0000638 && (isMultiRsp == FALSE)) {
639 cERROR(1, ("No task to wake, unknown frame received! "
640 "NumMids %d", midCount.counter));
641 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700642 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000643#ifdef CONFIG_CIFS_DEBUG2
644 cifs_dump_detail(smb_buffer);
645 cifs_dump_mids(server);
646#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000647
Steve Frenche4eb2952005-04-28 22:41:09 -0700648 }
649 } /* end while !EXITING */
650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 spin_lock(&GlobalMid_Lock);
652 server->tcpStatus = CifsExiting;
653 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700654 /* check if we have blocked requests that need to free */
655 /* Note that cifs_max_pending is normally 50, but
656 can be set at module install time to as little as two */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000657 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700658 atomic_set(&server->inFlight, cifs_max_pending - 1);
659 /* We do not want to set the max_pending too low or we
660 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000662 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700664 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 to the same server - they now will see the session is in exit state
666 and get out of SendReceive. */
667 wake_up_all(&server->request_q);
668 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700669 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000670
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000671 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 sock_release(csocket);
673 server->ssocket = NULL;
674 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700675 /* buffer usuallly freed in free_mid - need to free it here on exit */
676 if (bigbuf != NULL)
677 cifs_buf_release(bigbuf);
678 if (smallbuf != NULL)
679 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 read_lock(&GlobalSMBSeslock);
682 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700683 /* loop through server session structures attached to this and
684 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 list_for_each(tmp, &GlobalSMBSessionList) {
686 ses =
687 list_entry(tmp, struct cifsSesInfo,
688 cifsSessionList);
689 if (ses->server == server) {
690 ses->status = CifsExiting;
691 ses->server = NULL;
692 }
693 }
694 read_unlock(&GlobalSMBSeslock);
695 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700696 /* although we can not zero the server struct pointer yet,
697 since there are active requests which may depnd on them,
698 mark the corresponding SMB sessions as exiting too */
699 list_for_each(tmp, &GlobalSMBSessionList) {
700 ses = list_entry(tmp, struct cifsSesInfo,
701 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000702 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700703 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700704 }
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 spin_lock(&GlobalMid_Lock);
707 list_for_each(tmp, &server->pending_mid_q) {
708 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
709 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000710 cFYI(1, ("Clearing Mid 0x%x - waking up ",
711 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000713 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716 }
717 spin_unlock(&GlobalMid_Lock);
718 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700720 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 }
722
Steve Frenchf1914012005-08-18 09:37:34 -0700723 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000724 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700726 /* due to delays on oplock break requests, we need
727 to wait at least 45 seconds before giving up
728 on a request getting a response and going ahead
729 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700731 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 /* if threads still have not exited they are probably never
733 coming home not much else we can do but free the memory */
734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 write_lock(&GlobalSMBSeslock);
737 atomic_dec(&tcpSesAllocCount);
738 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700739
740 /* last chance to mark ses pointers invalid
741 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000742 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700743 kernel thread explicitly this might happen) */
744 list_for_each(tmp, &GlobalSMBSessionList) {
745 ses = list_entry(tmp, struct cifsSesInfo,
746 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000747 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700748 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700751
752 kfree(server);
Steve French26f57362007-08-30 22:09:15 +0000753 if (length > 0)
754 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
755 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return 0;
758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760static int
Steve French50c2f752007-07-13 00:33:32 +0000761cifs_parse_mount_options(char *options, const char *devname,
762 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 char *value;
765 char *data;
766 unsigned int temp_len, i, j;
767 char separator[2];
768
769 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000770 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Linus Torvalds12e36b22006-10-13 08:09:29 -0700772 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000773 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000774 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700775 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000776 int n = strnlen(nodename, 15);
777 memset(vol->source_rfc1001_name, 0x20, 15);
778 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000779 /* does not have to be perfect mapping since field is
780 informational, only used for servers that do not support
781 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700782 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 }
785 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700786 /* null target name indicates to use *SMBSERVR default called name
787 if we end up sending RFC1001 session initialize */
788 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 vol->linux_uid = current->uid; /* current->euid instead? */
790 vol->linux_gid = current->gid;
791 vol->dir_mode = S_IRWXUGO;
792 /* 2767 perms indicate mandatory locking support */
793 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
794
795 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
796 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700797 /* default is always to request posix paths. */
798 vol->posix_paths = 1;
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 if (!options)
801 return 1;
802
Steve French50c2f752007-07-13 00:33:32 +0000803 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000804 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 separator[0] = options[4];
806 options += 5;
807 } else {
Steve French467a8f82007-06-27 22:41:32 +0000808 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 }
810 }
Steve French50c2f752007-07-13 00:33:32 +0000811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 while ((data = strsep(&options, separator)) != NULL) {
813 if (!*data)
814 continue;
815 if ((value = strchr(data, '=')) != NULL)
816 *value++ = '\0';
817
Steve French50c2f752007-07-13 00:33:32 +0000818 /* Have to parse this before we parse for "user" */
819 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000821 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 vol->no_xattr = 1;
823 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000824 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 printk(KERN_WARNING
826 "CIFS: invalid or missing username\n");
827 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000828 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000829 /* null user, ie anonymous, authentication */
830 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 }
832 if (strnlen(value, 200) < 200) {
833 vol->username = value;
834 } else {
835 printk(KERN_WARNING "CIFS: username too long\n");
836 return 1;
837 }
838 } else if (strnicmp(data, "pass", 4) == 0) {
839 if (!value) {
840 vol->password = NULL;
841 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000842 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 /* check if string begins with double comma
844 since that would mean the password really
845 does start with a comma, and would not
846 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000847 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 vol->password = NULL;
849 continue;
850 }
851 }
852 temp_len = strlen(value);
853 /* removed password length check, NTLM passwords
854 can be arbitrarily long */
855
Steve French50c2f752007-07-13 00:33:32 +0000856 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 prematurely null terminated. Commas in password are
858 specified across the cifs mount interface by a double
859 comma ie ,, and a comma used as in other cases ie ','
860 as a parameter delimiter/separator is single and due
861 to the strsep above is temporarily zeroed. */
862
863 /* NB: password legally can have multiple commas and
864 the only illegal character in a password is null */
865
Steve French50c2f752007-07-13 00:33:32 +0000866 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700867 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 /* reinsert comma */
869 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000870 temp_len += 2; /* move after second comma */
871 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000873 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700874 separator[0]) {
875 /* skip second comma */
876 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000877 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 /* single comma indicating start
879 of next parm */
880 break;
881 }
882 }
883 temp_len++;
884 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000885 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 options = NULL;
887 } else {
888 value[temp_len] = 0;
889 /* point option to start of next parm */
890 options = value + temp_len + 1;
891 }
Steve French50c2f752007-07-13 00:33:32 +0000892 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 double commas to singles. Note that this ends up
894 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700895 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000896 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000897 printk(KERN_WARNING "CIFS: no memory "
898 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700899 return 1;
900 }
Steve French50c2f752007-07-13 00:33:32 +0000901 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000903 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700904 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 /* skip second comma */
906 i++;
907 }
908 }
909 vol->password[j] = 0;
910 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700911 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000912 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000913 printk(KERN_WARNING "CIFS: no memory "
914 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700915 return 1;
916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 strcpy(vol->password, value);
918 }
919 } else if (strnicmp(data, "ip", 2) == 0) {
920 if (!value || !*value) {
921 vol->UNCip = NULL;
922 } else if (strnlen(value, 35) < 35) {
923 vol->UNCip = value;
924 } else {
Steve French50c2f752007-07-13 00:33:32 +0000925 printk(KERN_WARNING "CIFS: ip address "
926 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 return 1;
928 }
Steve French50c2f752007-07-13 00:33:32 +0000929 } else if (strnicmp(data, "sec", 3) == 0) {
930 if (!value || !*value) {
931 cERROR(1, ("no security value specified"));
932 continue;
933 } else if (strnicmp(value, "krb5i", 5) == 0) {
934 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000935 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800936 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000937 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
938 CIFSSEC_MAY_KRB5; */
939 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800940 return 1;
941 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000942 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800943 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000944 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000945 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800946 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000947 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800948 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000949 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000950 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800951 } else if (strnicmp(value, "ntlm", 4) == 0) {
952 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000953 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800954 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000955 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000956 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000957#ifdef CONFIG_CIFS_WEAK_PW_HASH
958 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000959 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000960#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800961 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000962 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000963 } else {
964 cERROR(1, ("bad security option: %s", value));
965 return 1;
966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 } else if ((strnicmp(data, "unc", 3) == 0)
968 || (strnicmp(data, "target", 6) == 0)
969 || (strnicmp(data, "path", 4) == 0)) {
970 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +0000971 printk(KERN_WARNING "CIFS: invalid path to "
972 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return 1; /* needs_arg; */
974 }
975 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +0000976 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000977 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return 1;
Steve French50c2f752007-07-13 00:33:32 +0000979 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (strncmp(vol->UNC, "//", 2) == 0) {
981 vol->UNC[0] = '\\';
982 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +0000983 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +0000985 "CIFS: UNC Path does not begin "
986 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 return 1;
988 }
989 } else {
990 printk(KERN_WARNING "CIFS: UNC name too long\n");
991 return 1;
992 }
993 } else if ((strnicmp(data, "domain", 3) == 0)
994 || (strnicmp(data, "workgroup", 5) == 0)) {
995 if (!value || !*value) {
996 printk(KERN_WARNING "CIFS: invalid domain name\n");
997 return 1; /* needs_arg; */
998 }
999 /* BB are there cases in which a comma can be valid in
1000 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001001 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 vol->domainname = value;
1003 cFYI(1, ("Domain name set"));
1004 } else {
Steve French50c2f752007-07-13 00:33:32 +00001005 printk(KERN_WARNING "CIFS: domain name too "
1006 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return 1;
1008 }
Steve French50c2f752007-07-13 00:33:32 +00001009 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1010 if (!value || !*value) {
1011 printk(KERN_WARNING
1012 "CIFS: invalid path prefix\n");
1013 return 1; /* needs_argument */
1014 }
1015 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001016 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001017 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001018 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1019 if (vol->prepath == NULL)
1020 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001021 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001022 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001023 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001024 } else
Steve French50c2f752007-07-13 00:33:32 +00001025 strcpy(vol->prepath, value);
1026 cFYI(1, ("prefix path %s", vol->prepath));
1027 } else {
1028 printk(KERN_WARNING "CIFS: prefix too long\n");
1029 return 1;
1030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 } else if (strnicmp(data, "iocharset", 9) == 0) {
1032 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001033 printk(KERN_WARNING "CIFS: invalid iocharset "
1034 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return 1; /* needs_arg; */
1036 }
1037 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001038 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001040 /* if iocharset not set then load_nls_default
1041 is used by caller */
1042 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 } else {
Steve French63135e02007-07-17 17:34:02 +00001044 printk(KERN_WARNING "CIFS: iocharset name "
1045 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return 1;
1047 }
1048 } else if (strnicmp(data, "uid", 3) == 0) {
1049 if (value && *value) {
1050 vol->linux_uid =
1051 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001052 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054 } else if (strnicmp(data, "gid", 3) == 0) {
1055 if (value && *value) {
1056 vol->linux_gid =
1057 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001058 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
1060 } else if (strnicmp(data, "file_mode", 4) == 0) {
1061 if (value && *value) {
1062 vol->file_mode =
1063 simple_strtoul(value, &value, 0);
1064 }
1065 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1066 if (value && *value) {
1067 vol->dir_mode =
1068 simple_strtoul(value, &value, 0);
1069 }
1070 } else if (strnicmp(data, "dirmode", 4) == 0) {
1071 if (value && *value) {
1072 vol->dir_mode =
1073 simple_strtoul(value, &value, 0);
1074 }
1075 } else if (strnicmp(data, "port", 4) == 0) {
1076 if (value && *value) {
1077 vol->port =
1078 simple_strtoul(value, &value, 0);
1079 }
1080 } else if (strnicmp(data, "rsize", 5) == 0) {
1081 if (value && *value) {
1082 vol->rsize =
1083 simple_strtoul(value, &value, 0);
1084 }
1085 } else if (strnicmp(data, "wsize", 5) == 0) {
1086 if (value && *value) {
1087 vol->wsize =
1088 simple_strtoul(value, &value, 0);
1089 }
1090 } else if (strnicmp(data, "sockopt", 5) == 0) {
1091 if (value && *value) {
1092 vol->sockopt =
1093 simple_strtoul(value, &value, 0);
1094 }
1095 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1096 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001097 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 } else {
Steve French50c2f752007-07-13 00:33:32 +00001099 memset(vol->source_rfc1001_name, 0x20, 15);
1100 for (i = 0; i < 15; i++) {
1101 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 valid in this workstation netbios name (and need
1103 special handling)? */
1104
1105 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001106 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 break;
Steve French50c2f752007-07-13 00:33:32 +00001108 else
1109 vol->source_rfc1001_name[i] =
1110 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
1112 /* The string has 16th byte zero still from
1113 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001114 if ((i == 15) && (value[i] != 0))
1115 printk(KERN_WARNING "CIFS: netbiosname"
1116 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001117 }
1118 } else if (strnicmp(data, "servern", 7) == 0) {
1119 /* servernetbiosname specified override *SMBSERVER */
1120 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001121 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001122 } else {
1123 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001124 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001125
Steve French50c2f752007-07-13 00:33:32 +00001126 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001127 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001128 valid in this workstation netbios name
1129 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001130
Steve French50c2f752007-07-13 00:33:32 +00001131 /* user or mount helper must uppercase
1132 the netbiosname */
1133 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001134 break;
1135 else
Steve French50c2f752007-07-13 00:33:32 +00001136 vol->target_rfc1001_name[i] =
1137 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001138 }
1139 /* The string has 16th byte zero still from
1140 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001141 if ((i == 15) && (value[i] != 0))
1142 printk(KERN_WARNING "CIFS: server net"
1143 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 }
1145 } else if (strnicmp(data, "credentials", 4) == 0) {
1146 /* ignore */
1147 } else if (strnicmp(data, "version", 3) == 0) {
1148 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001149 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 /* ignore */
1151 } else if (strnicmp(data, "rw", 2) == 0) {
1152 vol->rw = TRUE;
1153 } else if ((strnicmp(data, "suid", 4) == 0) ||
1154 (strnicmp(data, "nosuid", 6) == 0) ||
1155 (strnicmp(data, "exec", 4) == 0) ||
1156 (strnicmp(data, "noexec", 6) == 0) ||
1157 (strnicmp(data, "nodev", 5) == 0) ||
1158 (strnicmp(data, "noauto", 6) == 0) ||
1159 (strnicmp(data, "dev", 3) == 0)) {
1160 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001161 uses these opts to set flags, and the flags are read
1162 by the kernel vfs layer before we get here (ie
1163 before read super) so there is no point trying to
1164 parse these options again and set anything and it
1165 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 continue;
1167 } else if (strnicmp(data, "ro", 2) == 0) {
1168 vol->rw = FALSE;
1169 } else if (strnicmp(data, "hard", 4) == 0) {
1170 vol->retry = 1;
1171 } else if (strnicmp(data, "soft", 4) == 0) {
1172 vol->retry = 0;
1173 } else if (strnicmp(data, "perm", 4) == 0) {
1174 vol->noperm = 0;
1175 } else if (strnicmp(data, "noperm", 6) == 0) {
1176 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001177 } else if (strnicmp(data, "mapchars", 8) == 0) {
1178 vol->remap = 1;
1179 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1180 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001181 } else if (strnicmp(data, "sfu", 3) == 0) {
1182 vol->sfu_emul = 1;
1183 } else if (strnicmp(data, "nosfu", 5) == 0) {
1184 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001185 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1186 vol->posix_paths = 1;
1187 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1188 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001189 } else if (strnicmp(data, "nounix", 6) == 0) {
1190 vol->no_linux_ext = 1;
1191 } else if (strnicmp(data, "nolinux", 7) == 0) {
1192 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001193 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001194 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001195 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001196 } else if (strnicmp(data, "brl", 3) == 0) {
1197 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001198 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001199 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001200 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001201 /* turn off mandatory locking in mode
1202 if remote locking is turned off since the
1203 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001204 if (vol->file_mode ==
1205 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001206 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 } else if (strnicmp(data, "setuids", 7) == 0) {
1208 vol->setuids = 1;
1209 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1210 vol->setuids = 0;
1211 } else if (strnicmp(data, "nohard", 6) == 0) {
1212 vol->retry = 0;
1213 } else if (strnicmp(data, "nosoft", 6) == 0) {
1214 vol->retry = 1;
1215 } else if (strnicmp(data, "nointr", 6) == 0) {
1216 vol->intr = 0;
1217 } else if (strnicmp(data, "intr", 4) == 0) {
1218 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001219 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001221 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001223 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001224 vol->cifs_acl = 1;
1225 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1226 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001227 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001229 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001231 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001232 vol->secFlg |= CIFSSEC_MUST_SIGN;
1233/* } else if (strnicmp(data, "seal",4) == 0) {
1234 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Steve French50c2f752007-07-13 00:33:32 +00001235 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001237 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001239 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 if (!value || !*value) {
1241 vol->in6_addr = NULL;
1242 } else if (strnlen(value, 49) == 48) {
1243 vol->in6_addr = value;
1244 } else {
Steve French50c2f752007-07-13 00:33:32 +00001245 printk(KERN_WARNING "CIFS: ip v6 address not "
1246 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 return 1;
1248 }
1249 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001250 printk(KERN_WARNING "CIFS: Mount option noac not "
1251 "supported. Instead set "
1252 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 } else
Steve French50c2f752007-07-13 00:33:32 +00001254 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1255 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 }
1257 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001258 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001259 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1260 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 return 1;
1262 }
1263 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001264 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001265 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001267 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 if (strncmp(vol->UNC, "//", 2) == 0) {
1269 vol->UNC[0] = '\\';
1270 vol->UNC[1] = '\\';
1271 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001272 printk(KERN_WARNING "CIFS: UNC Path does not "
1273 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 return 1;
1275 }
1276 } else {
1277 printk(KERN_WARNING "CIFS: UNC name too long\n");
1278 return 1;
1279 }
1280 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001281 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 vol->UNCip = &vol->UNC[2];
1283
1284 return 0;
1285}
1286
1287static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001288cifs_find_tcp_session(struct in_addr *target_ip_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 struct in6_addr *target_ip6_addr,
1290 char *userName, struct TCP_Server_Info **psrvTcp)
1291{
1292 struct list_head *tmp;
1293 struct cifsSesInfo *ses;
1294 *psrvTcp = NULL;
1295 read_lock(&GlobalSMBSeslock);
1296
1297 list_for_each(tmp, &GlobalSMBSessionList) {
1298 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1299 if (ses->server) {
Steve French50c2f752007-07-13 00:33:32 +00001300 if ((target_ip_addr &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 (ses->server->addr.sockAddr.sin_addr.s_addr
1302 == target_ip_addr->s_addr)) || (target_ip6_addr
1303 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
Steve French50c2f752007-07-13 00:33:32 +00001304 target_ip6_addr, sizeof(*target_ip6_addr)))) {
1305 /* BB lock server and tcp session and increment
1306 use count here?? */
1307
1308 /* found a match on the TCP session */
1309 *psrvTcp = ses->server;
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 /* BB check if reconnection needed */
1312 if (strncmp
1313 (ses->userName, userName,
1314 MAX_USERNAME_SIZE) == 0){
1315 read_unlock(&GlobalSMBSeslock);
Steve French50c2f752007-07-13 00:33:32 +00001316 /* Found exact match on both TCP and
1317 SMB sessions */
1318 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 }
1320 }
1321 }
1322 /* else tcp and smb sessions need reconnection */
1323 }
1324 read_unlock(&GlobalSMBSeslock);
1325 return NULL;
1326}
1327
1328static struct cifsTconInfo *
1329find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1330{
1331 struct list_head *tmp;
1332 struct cifsTconInfo *tcon;
1333
1334 read_lock(&GlobalSMBSeslock);
1335 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001336 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1338 if (tcon->ses) {
1339 if (tcon->ses->server) {
1340 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001341 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 tcon->ses->server->addr.sockAddr.sin_addr.
1343 s_addr, new_target_ip_addr));
1344 if (tcon->ses->server->addr.sockAddr.sin_addr.
1345 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001346 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 /* found a match on the TCP session */
1348 /* BB check if reconnection needed */
Steve French50c2f752007-07-13 00:33:32 +00001349 cFYI(1,
1350 ("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 tcon->treeName, uncName));
1352 if (strncmp
1353 (tcon->treeName, uncName,
1354 MAX_TREE_SIZE) == 0) {
1355 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001356 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 tcon->treeName, uncName));
1358 if (strncmp
1359 (tcon->ses->userName,
1360 userName,
1361 MAX_USERNAME_SIZE) == 0) {
1362 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001363 /* matched smb session
1364 (user name */
1365 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 }
1367 }
1368 }
1369 }
1370 }
1371 }
1372 read_unlock(&GlobalSMBSeslock);
1373 return NULL;
1374}
1375
1376int
1377connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001378 const char *old_path, const struct nls_table *nls_codepage,
1379 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
1381 unsigned char *referrals = NULL;
1382 unsigned int num_referrals;
1383 int rc = 0;
1384
Steve French50c2f752007-07-13 00:33:32 +00001385 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001386 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 /* BB Add in code to: if valid refrl, if not ip address contact
Steve French50c2f752007-07-13 00:33:32 +00001389 the helper that resolves tcp names, mount to it, try to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 tcon to it unmount it if fail */
1391
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001392 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 return rc;
1395}
1396
1397int
Steve French50c2f752007-07-13 00:33:32 +00001398get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1399 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1400 unsigned char **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401{
1402 char *temp_unc;
1403 int rc = 0;
1404
1405 *pnum_referrals = 0;
1406
1407 if (pSesInfo->ipc_tid == 0) {
1408 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001409 strnlen(pSesInfo->serverName,
1410 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 + 1 + 4 /* slash IPC$ */ + 2,
1412 GFP_KERNEL);
1413 if (temp_unc == NULL)
1414 return -ENOMEM;
1415 temp_unc[0] = '\\';
1416 temp_unc[1] = '\\';
1417 strcpy(temp_unc + 2, pSesInfo->serverName);
1418 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1419 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1420 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001421 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 kfree(temp_unc);
1423 }
1424 if (rc == 0)
1425 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001426 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
1428 return rc;
1429}
1430
1431/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001432static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433{
Steve French50c2f752007-07-13 00:33:32 +00001434 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
Steve French50c2f752007-07-13 00:33:32 +00001436 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 /* mask a nibble at a time and encode */
1438 target[j] = 'A' + (0x0F & (source[i] >> 4));
1439 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001440 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 }
1442
1443}
1444
1445
1446static int
Steve French50c2f752007-07-13 00:33:32 +00001447ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1448 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449{
1450 int rc = 0;
1451 int connected = 0;
1452 __be16 orig_port = 0;
1453
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001454 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001455 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1456 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001458 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 *csocket = NULL;
1460 return rc;
1461 } else {
1462 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001463 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001464 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 }
1466 }
1467
1468 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001469 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 rc = (*csocket)->ops->connect(*csocket,
1471 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001472 sizeof (struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 if (rc >= 0)
1474 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001477 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001478 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 later if fall back ports fail this time */
1480 orig_port = psin_server->sin_port;
1481
1482 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001483 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 psin_server->sin_port = htons(CIFS_PORT);
1485
1486 rc = (*csocket)->ops->connect(*csocket,
1487 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001488 sizeof (struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (rc >= 0)
1490 connected = 1;
1491 }
1492 }
1493 if (!connected) {
1494 psin_server->sin_port = htons(RFC1001_PORT);
1495 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001496 psin_server,
1497 sizeof (struct sockaddr_in), 0);
1498 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 connected = 1;
1500 }
1501
1502 /* give up here - unless we want to retry on different
1503 protocol families some day */
1504 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001505 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001507 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 sock_release(*csocket);
1509 *csocket = NULL;
1510 return rc;
1511 }
Steve French50c2f752007-07-13 00:33:32 +00001512 /* Eventually check for other socket options to change from
1513 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001515 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1516 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001517 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001519 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001520 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001521 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001522 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001523 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
1525 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001526 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001528 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001530 struct rfc1002_session_packet *ses_init_buf;
1531 struct smb_hdr *smb_buf;
1532 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1533 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001534 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001536 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001537 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1538 target_name, 16);
1539 } else {
1540 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001541 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001542 }
1543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 ses_init_buf->trailer.session_req.calling_len = 32;
1545 /* calling name ends in null (byte 16) from old smb
1546 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001547 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001549 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 } else {
1551 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001552 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 }
1554 ses_init_buf->trailer.session_req.scope1 = 0;
1555 ses_init_buf->trailer.session_req.scope2 = 0;
1556 smb_buf = (struct smb_hdr *)ses_init_buf;
1557 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1558 smb_buf->smb_buf_length = 0x81000044;
1559 rc = smb_send(*csocket, smb_buf, 0x44,
1560 (struct sockaddr *)psin_server);
1561 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001562 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001563 requires very short break before negprot
1564 presumably because not expecting negprot
1565 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001566 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001567 complicating the code and causes no
1568 significant slowing down on mount
1569 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 }
Steve French50c2f752007-07-13 00:33:32 +00001571 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001573
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
Steve French50c2f752007-07-13 00:33:32 +00001575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 return rc;
1577}
1578
1579static int
1580ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1581{
1582 int rc = 0;
1583 int connected = 0;
1584 __be16 orig_port = 0;
1585
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001586 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001587 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1588 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001590 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 *csocket = NULL;
1592 return rc;
1593 } else {
1594 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001595 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 (*csocket)->sk->sk_allocation = GFP_NOFS;
1597 }
1598 }
1599
1600 psin_server->sin6_family = AF_INET6;
1601
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001602 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 rc = (*csocket)->ops->connect(*csocket,
1604 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001605 sizeof (struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 if (rc >= 0)
1607 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001610 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001611 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 later if fall back ports fail this time */
1613
1614 orig_port = psin_server->sin6_port;
1615 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001616 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 psin_server->sin6_port = htons(CIFS_PORT);
1618
1619 rc = (*csocket)->ops->connect(*csocket,
1620 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001621 sizeof (struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (rc >= 0)
1623 connected = 1;
1624 }
1625 }
1626 if (!connected) {
1627 psin_server->sin6_port = htons(RFC1001_PORT);
1628 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001629 psin_server, sizeof (struct sockaddr_in6), 0);
1630 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 connected = 1;
1632 }
1633
1634 /* give up here - unless we want to retry on different
1635 protocol families some day */
1636 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001637 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001639 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 sock_release(*csocket);
1641 *csocket = NULL;
1642 return rc;
1643 }
Steve French50c2f752007-07-13 00:33:32 +00001644 /* Eventually check for other socket options to change from
1645 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 user space buffer */
1647 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 return rc;
1650}
1651
Steve French50c2f752007-07-13 00:33:32 +00001652void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1653 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001654{
1655 /* if we are reconnecting then should we check to see if
1656 * any requested capabilities changed locally e.g. via
1657 * remount but we can not do much about it here
1658 * if they have (even if we could detect it by the following)
1659 * Perhaps we could add a backpointer to array of sb from tcon
1660 * or if we change to make all sb to same share the same
1661 * sb as NFS - then we only have one backpointer to sb.
1662 * What if we wanted to mount the server share twice once with
1663 * and once without posixacls or posix paths? */
1664 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001665
Steve Frenchc18c8422007-07-18 23:21:09 +00001666 if (vol_info && vol_info->no_linux_ext) {
1667 tcon->fsUnixInfo.Capability = 0;
1668 tcon->unix_ext = 0; /* Unix Extensions disabled */
1669 cFYI(1, ("Linux protocol extensions disabled"));
1670 return;
1671 } else if (vol_info)
1672 tcon->unix_ext = 1; /* Unix Extensions supported */
1673
1674 if (tcon->unix_ext == 0) {
1675 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1676 return;
1677 }
Steve French50c2f752007-07-13 00:33:32 +00001678
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001679 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001680 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001681
Steve French8af18972007-02-14 04:42:51 +00001682 /* check for reconnect case in which we do not
1683 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001684 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001685 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001686 originally at mount time */
1687 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1688 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1689 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1690 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French8af18972007-02-14 04:42:51 +00001691 }
Steve French50c2f752007-07-13 00:33:32 +00001692
Steve French8af18972007-02-14 04:42:51 +00001693 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001694 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001695 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001696 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001697 cFYI(1, ("negotiated posix acl support"));
1698 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001699 sb->s_flags |= MS_POSIXACL;
1700 }
1701
Steve French75865f8c2007-06-24 18:30:48 +00001702 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001703 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001704 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001705 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001706 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001707 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001708 CIFS_MOUNT_POSIX_PATHS;
1709 }
Steve French50c2f752007-07-13 00:33:32 +00001710
Steve French984acfe2007-04-26 16:42:50 +00001711 /* We might be setting the path sep back to a different
1712 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001713 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001714 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001715 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001716
1717 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1718 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1719 CIFS_SB(sb)->rsize = 127 * 1024;
1720#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001721 cFYI(1, ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001722#endif
1723 }
1724 }
Steve French50c2f752007-07-13 00:33:32 +00001725
1726
1727 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001728#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001729 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001730 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001731 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001732 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001733 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001734 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001735 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001736 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001737 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001738 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001739 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001740 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001741 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001742 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001743#endif /* CIFS_DEBUG2 */
1744 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001745 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001746 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001747 } else
Steve French5a44b312007-09-20 15:16:24 +00001748 cERROR(1, ("Negotiating Unix capabilities "
1749 "with the server failed. Consider "
1750 "mounting with the Unix Extensions\n"
1751 "disabled, if problems are found, "
1752 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001753 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001754
Steve French8af18972007-02-14 04:42:51 +00001755 }
1756 }
1757}
1758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759int
1760cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1761 char *mount_data, const char *devname)
1762{
1763 int rc = 0;
1764 int xid;
1765 int address_type = AF_INET;
1766 struct socket *csocket = NULL;
1767 struct sockaddr_in sin_server;
1768 struct sockaddr_in6 sin_server6;
1769 struct smb_vol volume_info;
1770 struct cifsSesInfo *pSesInfo = NULL;
1771 struct cifsSesInfo *existingCifsSes = NULL;
1772 struct cifsTconInfo *tcon = NULL;
1773 struct TCP_Server_Info *srvTcp = NULL;
1774
1775 xid = GetXid();
1776
1777/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001778
1779 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001781 kfree(volume_info.UNC);
1782 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001783 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 FreeXid(xid);
1785 return -EINVAL;
1786 }
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 Layton8426c392007-05-05 03:27:49 +00001790 volume_info.username = NULL;
1791 } 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 */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001798 kfree(volume_info.UNC);
1799 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001800 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 FreeXid(xid);
1802 return -EINVAL;
1803 }
1804
1805 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001806 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1807 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001809 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001811 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1812 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001813 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 address_type = AF_INET6;
1815 } else {
1816 address_type = AF_INET;
1817 }
Steve French50c2f752007-07-13 00:33:32 +00001818
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001819 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001821 kfree(volume_info.UNC);
1822 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001823 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 FreeXid(xid);
1825 return -EINVAL;
1826 }
1827
1828 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1829 /* success */
1830 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001831 } else if (volume_info.UNCip) {
1832 /* BB using ip addr as server name to connect to the
1833 DFS root below */
1834 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001835 kfree(volume_info.UNC);
1836 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001837 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 FreeXid(xid);
1839 return -EINVAL;
1840 } else /* which servers DFS root would we conect to */ {
1841 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001842 ("CIFS mount error: No UNC path (e.g. -o "
1843 "unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001844 kfree(volume_info.UNC);
1845 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001846 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 FreeXid(xid);
1848 return -EINVAL;
1849 }
1850
1851 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001852 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 cifs_sb->local_nls = load_nls_default();
1854 /* load_nls_default can not return null */
1855 } else {
1856 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001857 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001858 cERROR(1, ("CIFS mount error: iocharset %s not found",
1859 volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001860 kfree(volume_info.UNC);
1861 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001862 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 FreeXid(xid);
1864 return -ELIBACC;
1865 }
1866 }
1867
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001868 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1870 NULL /* no ipv6 addr */,
1871 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001872 else if (address_type == AF_INET6) {
1873 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1875 &sin_server6.sin6_addr,
1876 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001877 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001878 kfree(volume_info.UNC);
1879 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001880 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 FreeXid(xid);
1882 return -EINVAL;
1883 }
1884
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001886 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001888 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 sin_server.sin_port = htons(volume_info.port);
1890 else
1891 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001892 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001893 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001894 /* BB should we allow ipv6 on port 139? */
1895 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001896 rc = ipv6_connect(&sin_server6, &csocket);
1897 } else
1898 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001899 volume_info.source_rfc1001_name,
1900 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001902 cERROR(1, ("Error connecting to IPv4 socket. "
1903 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001904 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001906 kfree(volume_info.UNC);
1907 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001908 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 FreeXid(xid);
1910 return rc;
1911 }
1912
1913 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1914 if (srvTcp == NULL) {
1915 rc = -ENOMEM;
1916 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001917 kfree(volume_info.UNC);
1918 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001919 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 FreeXid(xid);
1921 return rc;
1922 } else {
1923 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
Steve French50c2f752007-07-13 00:33:32 +00001924 memcpy(&srvTcp->addr.sockAddr, &sin_server,
1925 sizeof (struct sockaddr_in));
1926 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 /* BB Add code for ipv6 case too */
1928 srvTcp->ssocket = csocket;
1929 srvTcp->protocolType = IPV4;
1930 init_waitqueue_head(&srvTcp->response_q);
1931 init_waitqueue_head(&srvTcp->request_q);
1932 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1933 /* at this point we are the only ones with the pointer
1934 to the struct since the kernel thread not created yet
1935 so no need to spinlock this init of tcpStatus */
1936 srvTcp->tcpStatus = CifsNew;
1937 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001938 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001939 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001940 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001941 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001942 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001944 kfree(volume_info.UNC);
1945 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001946 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 FreeXid(xid);
1948 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001949 }
1950 wait_for_completion(&cifsd_complete);
1951 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001952 memcpy(srvTcp->workstation_RFC1001_name,
1953 volume_info.source_rfc1001_name, 16);
1954 memcpy(srvTcp->server_RFC1001_name,
1955 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001956 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 }
1958 }
1959
1960 if (existingCifsSes) {
1961 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001962 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001963 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 /* volume_info.UNC freed at end of function */
1965 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001966 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 pSesInfo = sesInfoAlloc();
1968 if (pSesInfo == NULL)
1969 rc = -ENOMEM;
1970 else {
1971 pSesInfo->server = srvTcp;
1972 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1973 NIPQUAD(sin_server.sin_addr.s_addr));
1974 }
1975
Steve French50c2f752007-07-13 00:33:32 +00001976 if (!rc) {
1977 /* volume_info.password freed at unmount */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 if (volume_info.password)
1979 pSesInfo->password = volume_info.password;
1980 if (volume_info.username)
1981 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00001982 volume_info.username,
1983 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001984 if (volume_info.domainname) {
1985 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00001986 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00001987 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001988 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001989 strcpy(pSesInfo->domainName,
1990 volume_info.domainname);
1991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001993 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001995 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00001996 rc = cifs_setup_session(xid, pSesInfo,
1997 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001999 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 atomic_inc(&srvTcp->socketUseCount);
2001 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002002 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 }
Steve French50c2f752007-07-13 00:33:32 +00002004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 /* search for existing tcon to this server share */
2006 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002007 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002008 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002009 volume_info.rsize));
2010 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002011 } else if ((volume_info.rsize) &&
2012 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002014 else /* default */
2015 cifs_sb->rsize = CIFSMaxBufSize;
2016
Steve French4523cc32007-04-30 20:13:06 +00002017 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002018 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002019 volume_info.wsize));
2020 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002021 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 cifs_sb->wsize = volume_info.wsize;
2023 else
Steve French50c2f752007-07-13 00:33:32 +00002024 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002025 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2026 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002027 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002028 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002029 RFC1001 does not describe what happens when frame
2030 bigger than 128K is sent so use that as max in
2031 conjunction with 52K kvec constraint on arch with 4K
2032 page size */
2033
Steve French4523cc32007-04-30 20:13:06 +00002034 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002035 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002036 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002037 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
Steve French2fe87f02006-09-21 07:02:52 +00002039 /* calculate prepath */
2040 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002041 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002042 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2043 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
2044 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002045 } else
Steve French2fe87f02006-09-21 07:02:52 +00002046 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 cifs_sb->mnt_uid = volume_info.linux_uid;
2048 cifs_sb->mnt_gid = volume_info.linux_gid;
2049 cifs_sb->mnt_file_mode = volume_info.file_mode;
2050 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002051 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2052 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
Steve French4523cc32007-04-30 20:13:06 +00002054 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002056 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002058 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002060 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002061 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002062 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002064 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002065 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002066 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002067 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002068 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002069 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002070 if (volume_info.override_uid)
2071 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2072 if (volume_info.override_gid)
2073 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2074 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002075 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2077 }
2078
2079 tcon =
2080 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2081 volume_info.username);
2082 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002083 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 /* we can have only one retry value for a connection
2085 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002086 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 for the retry flag is used */
2088 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002089 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 } else {
2091 tcon = tconInfoAlloc();
2092 if (tcon == NULL)
2093 rc = -ENOMEM;
2094 else {
Steve French50c2f752007-07-13 00:33:32 +00002095 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002096 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Steve French50c2f752007-07-13 00:33:32 +00002098 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002099 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2101 && (strchr(volume_info.UNC + 3, '/') ==
2102 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002103 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002104 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002105 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002106 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002107 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 FreeXid(xid);
2109 return -ENODEV;
2110 } else {
Steve French8af18972007-02-14 04:42:51 +00002111 /* BB Do we need to wrap sesSem around
2112 * this TCon call and Unix SetFS as
2113 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002114 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 volume_info.UNC,
2116 tcon, cifs_sb->local_nls);
2117 cFYI(1, ("CIFS Tcon rc = %d", rc));
2118 }
2119 if (!rc) {
2120 atomic_inc(&pSesInfo->inUse);
2121 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002122 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 }
2124 }
2125 }
2126 }
Steve French4523cc32007-04-30 20:13:06 +00002127 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2129 sb->s_maxbytes = (u64) 1 << 63;
2130 } else
2131 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2132 }
2133
Steve French8af18972007-02-14 04:42:51 +00002134 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 sb->s_time_gran = 100;
2136
2137/* on error free sesinfo and tcon struct if needed */
2138 if (rc) {
2139 /* if session setup failed, use count is zero but
2140 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002141 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 spin_lock(&GlobalMid_Lock);
2143 srvTcp->tcpStatus = CifsExiting;
2144 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002145 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002146 struct task_struct *tsk;
2147 /* If we could verify that kthread_stop would
2148 always wake up processes blocked in
2149 tcp in recv_mesg then we could remove the
2150 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002151 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002152 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002153 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002154 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 }
2157 /* If find_unc succeeded then rc == 0 so we can not end */
2158 if (tcon) /* up accidently freeing someone elses tcon struct */
2159 tconInfoFree(tcon);
2160 if (existingCifsSes == NULL) {
2161 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002162 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 (pSesInfo->status == CifsGood)) {
2164 int temp_rc;
2165 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2166 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002167 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002168 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002169 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002170 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002171 force_sig(SIGKILL,
2172 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002173 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002174 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002175 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 } else
2178 cFYI(1, ("No session or bad tcon"));
2179 sesInfoFree(pSesInfo);
2180 /* pSesInfo = NULL; */
2181 }
2182 }
2183 } else {
2184 atomic_inc(&tcon->useCount);
2185 cifs_sb->tcon = tcon;
2186 tcon->ses = pSesInfo;
2187
Steve French82940a42006-03-02 03:24:57 +00002188 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002189 if (!tcon->ipc) {
2190 CIFSSMBQFSDeviceInfo(xid, tcon);
2191 CIFSSMBQFSAttributeInfo(xid, tcon);
2192 }
Steve French50c2f752007-07-13 00:33:32 +00002193
Steve French8af18972007-02-14 04:42:51 +00002194 /* tell server which Unix caps we support */
2195 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002196 /* reset of caps checks mount to see if unix extensions
2197 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002198 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002199 else
2200 tcon->unix_ext = 0; /* server does not support them */
2201
2202 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002203 cifs_sb->rsize = 1024 * 127;
2204#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchc18c8422007-07-18 23:21:09 +00002205 cFYI(1, ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002206#endif
Steve French75865f8c2007-06-24 18:30:48 +00002207 }
Steve French3e844692005-10-03 13:37:24 -07002208 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2209 cifs_sb->wsize = min(cifs_sb->wsize,
2210 (tcon->ses->server->maxBuf -
2211 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002212 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002213 cifs_sb->rsize = min(cifs_sb->rsize,
2214 (tcon->ses->server->maxBuf -
2215 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 }
2217
2218 /* volume_info.password is freed above when existing session found
2219 (in which case it is not needed anymore) but when new sesion is created
2220 the password ptr is put in the new session structure (in which case the
2221 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002222 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002223 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 FreeXid(xid);
2225 return rc;
2226}
2227
2228static int
2229CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002230 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 const struct nls_table *nls_codepage)
2232{
2233 struct smb_hdr *smb_buffer;
2234 struct smb_hdr *smb_buffer_response;
2235 SESSION_SETUP_ANDX *pSMB;
2236 SESSION_SETUP_ANDX *pSMBr;
2237 char *bcc_ptr;
2238 char *user;
2239 char *domain;
2240 int rc = 0;
2241 int remaining_words = 0;
2242 int bytes_returned = 0;
2243 int len;
2244 __u32 capabilities;
2245 __u16 count;
2246
Steve Frencheeac8042006-01-13 21:34:58 -08002247 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002248 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 return -EINVAL;
2250 user = ses->userName;
2251 domain = ses->domainName;
2252 smb_buffer = cifs_buf_get();
2253 if (smb_buffer == NULL) {
2254 return -ENOMEM;
2255 }
2256 smb_buffer_response = smb_buffer;
2257 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2258
2259 /* send SMBsessionSetup here */
2260 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2261 NULL /* no tCon exists yet */ , 13 /* wct */ );
2262
Steve French1982c342005-08-17 12:38:22 -07002263 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 pSMB->req_no_secext.AndXCommand = 0xFF;
2265 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2266 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2267
Steve French50c2f752007-07-13 00:33:32 +00002268 if (ses->server->secMode &
2269 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2271
2272 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2273 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2274 if (ses->capabilities & CAP_UNICODE) {
2275 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2276 capabilities |= CAP_UNICODE;
2277 }
2278 if (ses->capabilities & CAP_STATUS32) {
2279 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2280 capabilities |= CAP_STATUS32;
2281 }
2282 if (ses->capabilities & CAP_DFS) {
2283 smb_buffer->Flags2 |= SMBFLG2_DFS;
2284 capabilities |= CAP_DFS;
2285 }
2286 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2287
Steve French50c2f752007-07-13 00:33:32 +00002288 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002289 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
2291 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002292 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002294 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2295 bcc_ptr += CIFS_SESS_KEY_SIZE;
2296 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2297 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299 if (ses->capabilities & CAP_UNICODE) {
2300 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2301 *bcc_ptr = 0;
2302 bcc_ptr++;
2303 }
Steve French4523cc32007-04-30 20:13:06 +00002304 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002305 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002306 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002308 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 nls_codepage);
2310 /* convert number of 16 bit words to bytes */
2311 bcc_ptr += 2 * bytes_returned;
2312 bcc_ptr += 2; /* trailing null */
2313 if (domain == NULL)
2314 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002315 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 "CIFS_LINUX_DOM", 32, nls_codepage);
2317 else
2318 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002319 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 nls_codepage);
2321 bcc_ptr += 2 * bytes_returned;
2322 bcc_ptr += 2;
2323 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002324 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 32, nls_codepage);
2326 bcc_ptr += 2 * bytes_returned;
2327 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002328 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 32, nls_codepage);
2330 bcc_ptr += 2 * bytes_returned;
2331 bcc_ptr += 2;
2332 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002333 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 64, nls_codepage);
2335 bcc_ptr += 2 * bytes_returned;
2336 bcc_ptr += 2;
2337 } else {
Steve French50c2f752007-07-13 00:33:32 +00002338 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 strncpy(bcc_ptr, user, 200);
2340 bcc_ptr += strnlen(user, 200);
2341 }
2342 *bcc_ptr = 0;
2343 bcc_ptr++;
2344 if (domain == NULL) {
2345 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2346 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2347 } else {
2348 strncpy(bcc_ptr, domain, 64);
2349 bcc_ptr += strnlen(domain, 64);
2350 *bcc_ptr = 0;
2351 bcc_ptr++;
2352 }
2353 strcpy(bcc_ptr, "Linux version ");
2354 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002355 strcpy(bcc_ptr, utsname()->release);
2356 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2358 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2359 }
2360 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2361 smb_buffer->smb_buf_length += count;
2362 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2363
2364 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2365 &bytes_returned, 1);
2366 if (rc) {
2367/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2368 } else if ((smb_buffer_response->WordCount == 3)
2369 || (smb_buffer_response->WordCount == 4)) {
2370 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2371 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2372 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002373 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2374 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2375 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002377 /* response can have either 3 or 4 word count - Samba sends 3 */
2378 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 if ((pSMBr->resp.hdr.WordCount == 3)
2380 || ((pSMBr->resp.hdr.WordCount == 4)
2381 && (blob_len < pSMBr->resp.ByteCount))) {
2382 if (pSMBr->resp.hdr.WordCount == 4)
2383 bcc_ptr += blob_len;
2384
2385 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2386 if ((long) (bcc_ptr) % 2) {
2387 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002388 (BCC(smb_buffer_response) - 1) / 2;
2389 /* Unicode strings must be word
2390 aligned */
2391 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 } else {
2393 remaining_words =
2394 BCC(smb_buffer_response) / 2;
2395 }
2396 len =
2397 UniStrnlen((wchar_t *) bcc_ptr,
2398 remaining_words - 1);
2399/* We look for obvious messed up bcc or strings in response so we do not go off
2400 the end since (at least) WIN2K and Windows XP have a major bug in not null
2401 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002402 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002403 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002404 ses->serverOS = kzalloc(2 * (len + 1),
2405 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002406 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002407 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002409 (__le16 *)bcc_ptr,
2410 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 bcc_ptr += 2 * (len + 1);
2412 remaining_words -= len + 1;
2413 ses->serverOS[2 * len] = 0;
2414 ses->serverOS[1 + (2 * len)] = 0;
2415 if (remaining_words > 0) {
2416 len = UniStrnlen((wchar_t *)bcc_ptr,
2417 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002418 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002419 ses->serverNOS = kzalloc(2 * (len + 1),
2420 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002421 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002422 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002424 (__le16 *)bcc_ptr,
2425 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 bcc_ptr += 2 * (len + 1);
2427 ses->serverNOS[2 * len] = 0;
2428 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002429 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002430 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002431 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 ses->flags |= CIFS_SES_NT4;
2433 }
2434 remaining_words -= len + 1;
2435 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002436 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002437 /* last string is not always null terminated
2438 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002439 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002440 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002442 kzalloc(2*(len+1),
2443 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002444 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002445 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002447 (__le16 *)bcc_ptr,
2448 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 bcc_ptr += 2 * (len + 1);
2450 ses->serverDomain[2*len] = 0;
2451 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002452 } else { /* else no more room so create
2453 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002454 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002455 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002456 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002457 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002458 }
Steve French50c2f752007-07-13 00:33:32 +00002459 } else { /* no room so create dummy domain
2460 and NOS string */
2461
Steve French433dc242005-04-28 22:41:08 -07002462 /* if these kcallocs fail not much we
2463 can do, but better to not fail the
2464 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002465 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002467 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002468 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002470 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 }
2472 } else { /* ASCII */
2473 len = strnlen(bcc_ptr, 1024);
2474 if (((long) bcc_ptr + len) - (long)
2475 pByteArea(smb_buffer_response)
2476 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002477 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002478 ses->serverOS = kzalloc(len + 1,
2479 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002480 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002481 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002482 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
2484 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002485 /* null terminate the string */
2486 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 bcc_ptr++;
2488
2489 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002490 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002491 ses->serverNOS = kzalloc(len + 1,
2492 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002493 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002494 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 strncpy(ses->serverNOS, bcc_ptr, len);
2496 bcc_ptr += len;
2497 bcc_ptr[0] = 0;
2498 bcc_ptr++;
2499
2500 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002501 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002502 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002503 ses->serverDomain = kzalloc(len + 1,
2504 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002505 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002506 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002507 strncpy(ses->serverDomain, bcc_ptr,
2508 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 bcc_ptr += len;
2510 bcc_ptr[0] = 0;
2511 bcc_ptr++;
2512 } else
2513 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002514 ("Variable field of length %d "
2515 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 len));
2517 }
2518 } else {
2519 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002520 (" Security Blob Length extends beyond "
2521 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
2523 } else {
2524 cERROR(1,
2525 (" Invalid Word count %d: ",
2526 smb_buffer_response->WordCount));
2527 rc = -EIO;
2528 }
Steve French433dc242005-04-28 22:41:08 -07002529sesssetup_nomem: /* do not return an error on nomem for the info strings,
2530 since that could make reconnection harder, and
2531 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 if (smb_buffer)
2533 cifs_buf_release(smb_buffer);
2534
2535 return rc;
2536}
2537
2538static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002540 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 const struct nls_table *nls_codepage)
2542{
2543 struct smb_hdr *smb_buffer;
2544 struct smb_hdr *smb_buffer_response;
2545 SESSION_SETUP_ANDX *pSMB;
2546 SESSION_SETUP_ANDX *pSMBr;
2547 char *bcc_ptr;
2548 char *domain;
2549 int rc = 0;
2550 int remaining_words = 0;
2551 int bytes_returned = 0;
2552 int len;
2553 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2554 PNEGOTIATE_MESSAGE SecurityBlob;
2555 PCHALLENGE_MESSAGE SecurityBlob2;
2556 __u32 negotiate_flags, capabilities;
2557 __u16 count;
2558
Steve French12b3b8f2006-02-09 21:12:47 +00002559 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002560 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 return -EINVAL;
2562 domain = ses->domainName;
2563 *pNTLMv2_flag = FALSE;
2564 smb_buffer = cifs_buf_get();
2565 if (smb_buffer == NULL) {
2566 return -ENOMEM;
2567 }
2568 smb_buffer_response = smb_buffer;
2569 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2570 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2571
2572 /* send SMBsessionSetup here */
2573 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2574 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002575
2576 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2578 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2579
2580 pSMB->req.AndXCommand = 0xFF;
2581 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2582 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2583
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002584 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2586
2587 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2588 CAP_EXTENDED_SECURITY;
2589 if (ses->capabilities & CAP_UNICODE) {
2590 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2591 capabilities |= CAP_UNICODE;
2592 }
2593 if (ses->capabilities & CAP_STATUS32) {
2594 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2595 capabilities |= CAP_STATUS32;
2596 }
2597 if (ses->capabilities & CAP_DFS) {
2598 smb_buffer->Flags2 |= SMBFLG2_DFS;
2599 capabilities |= CAP_DFS;
2600 }
2601 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2602
2603 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2604 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2605 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2606 SecurityBlob->MessageType = NtLmNegotiate;
2607 negotiate_flags =
2608 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002609 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2610 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002612 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002614/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002615 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 /* setup pointers to domain name and workstation name */
2617 bcc_ptr += SecurityBlobLength;
2618
2619 SecurityBlob->WorkstationName.Buffer = 0;
2620 SecurityBlob->WorkstationName.Length = 0;
2621 SecurityBlob->WorkstationName.MaximumLength = 0;
2622
Steve French12b3b8f2006-02-09 21:12:47 +00002623 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2624 along with username on auth request (ie the response to challenge) */
2625 SecurityBlob->DomainName.Buffer = 0;
2626 SecurityBlob->DomainName.Length = 0;
2627 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 if (ses->capabilities & CAP_UNICODE) {
2629 if ((long) bcc_ptr % 2) {
2630 *bcc_ptr = 0;
2631 bcc_ptr++;
2632 }
2633
2634 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002635 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 32, nls_codepage);
2637 bcc_ptr += 2 * bytes_returned;
2638 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002639 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 nls_codepage);
2641 bcc_ptr += 2 * bytes_returned;
2642 bcc_ptr += 2; /* null terminate Linux version */
2643 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002644 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 64, nls_codepage);
2646 bcc_ptr += 2 * bytes_returned;
2647 *(bcc_ptr + 1) = 0;
2648 *(bcc_ptr + 2) = 0;
2649 bcc_ptr += 2; /* null terminate network opsys string */
2650 *(bcc_ptr + 1) = 0;
2651 *(bcc_ptr + 2) = 0;
2652 bcc_ptr += 2; /* null domain */
2653 } else { /* ASCII */
2654 strcpy(bcc_ptr, "Linux version ");
2655 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002656 strcpy(bcc_ptr, utsname()->release);
2657 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2659 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2660 bcc_ptr++; /* empty domain field */
2661 *bcc_ptr = 0;
2662 }
2663 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2664 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2665 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2666 smb_buffer->smb_buf_length += count;
2667 pSMB->req.ByteCount = cpu_to_le16(count);
2668
2669 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2670 &bytes_returned, 1);
2671
2672 if (smb_buffer_response->Status.CifsError ==
2673 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2674 rc = 0;
2675
2676 if (rc) {
2677/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2678 } else if ((smb_buffer_response->WordCount == 3)
2679 || (smb_buffer_response->WordCount == 4)) {
2680 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2681 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2682
2683 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002684 cFYI(1, (" Guest login"));
2685 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
Steve French50c2f752007-07-13 00:33:32 +00002687 bcc_ptr = pByteArea(smb_buffer_response);
2688 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
2690 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2691 if (SecurityBlob2->MessageType != NtLmChallenge) {
2692 cFYI(1,
2693 ("Unexpected NTLMSSP message type received %d",
2694 SecurityBlob2->MessageType));
2695 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002696 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002697 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 if ((pSMBr->resp.hdr.WordCount == 3)
2699 || ((pSMBr->resp.hdr.WordCount == 4)
2700 && (blob_len <
2701 pSMBr->resp.ByteCount))) {
2702
2703 if (pSMBr->resp.hdr.WordCount == 4) {
2704 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002705 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 blob_len));
2707 }
2708
Steve French12b3b8f2006-02-09 21:12:47 +00002709 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710
2711 memcpy(ses->server->cryptKey,
2712 SecurityBlob2->Challenge,
2713 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002714 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002715 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 *pNTLMv2_flag = TRUE;
2717
Steve French50c2f752007-07-13 00:33:32 +00002718 if ((SecurityBlob2->NegotiateFlags &
2719 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002721 ses->server->secMode |=
2722 SECMODE_SIGN_REQUIRED;
2723 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002725 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 SECMODE_SIGN_ENABLED;
2727
2728 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2729 if ((long) (bcc_ptr) % 2) {
2730 remaining_words =
2731 (BCC(smb_buffer_response)
2732 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002733 /* Must word align unicode strings */
2734 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 } else {
2736 remaining_words =
2737 BCC
2738 (smb_buffer_response) / 2;
2739 }
2740 len =
2741 UniStrnlen((wchar_t *) bcc_ptr,
2742 remaining_words - 1);
2743/* We look for obvious messed up bcc or strings in response so we do not go off
2744 the end since (at least) WIN2K and Windows XP have a major bug in not null
2745 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002746 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002747 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002749 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002751 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 bcc_ptr, len,
2753 nls_codepage);
2754 bcc_ptr += 2 * (len + 1);
2755 remaining_words -= len + 1;
2756 ses->serverOS[2 * len] = 0;
2757 ses->serverOS[1 + (2 * len)] = 0;
2758 if (remaining_words > 0) {
2759 len = UniStrnlen((wchar_t *)
2760 bcc_ptr,
2761 remaining_words
2762 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002763 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002765 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 GFP_KERNEL);
2767 cifs_strfromUCS_le(ses->
2768 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002769 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 bcc_ptr,
2771 len,
2772 nls_codepage);
2773 bcc_ptr += 2 * (len + 1);
2774 ses->serverNOS[2 * len] = 0;
2775 ses->serverNOS[1 +
2776 (2 * len)] = 0;
2777 remaining_words -= len + 1;
2778 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002779 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2780 /* last string not always null terminated
2781 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002782 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002784 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 (len +
2786 1),
2787 GFP_KERNEL);
2788 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002789 (ses->serverDomain,
2790 (__le16 *)bcc_ptr,
2791 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 bcc_ptr +=
2793 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002794 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002796 ses->serverDomain
2797 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 = 0;
2799 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002800 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002801 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002803 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002807 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002809 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002810 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002812 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 }
2814 } else { /* ASCII */
2815 len = strnlen(bcc_ptr, 1024);
2816 if (((long) bcc_ptr + len) - (long)
2817 pByteArea(smb_buffer_response)
2818 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002819 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002820 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002822 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 GFP_KERNEL);
2824 strncpy(ses->serverOS,
2825 bcc_ptr, len);
2826
2827 bcc_ptr += len;
2828 bcc_ptr[0] = 0; /* null terminate string */
2829 bcc_ptr++;
2830
2831 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002832 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002834 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 GFP_KERNEL);
2836 strncpy(ses->serverNOS, bcc_ptr, len);
2837 bcc_ptr += len;
2838 bcc_ptr[0] = 0;
2839 bcc_ptr++;
2840
2841 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002842 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002844 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002846 strncpy(ses->serverDomain,
2847 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 bcc_ptr += len;
2849 bcc_ptr[0] = 0;
2850 bcc_ptr++;
2851 } else
2852 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002853 ("field of length %d "
2854 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 len));
2856 }
2857 } else {
Steve French50c2f752007-07-13 00:33:32 +00002858 cERROR(1, ("Security Blob Length extends beyond"
2859 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 }
2861 } else {
2862 cERROR(1, ("No session structure passed in."));
2863 }
2864 } else {
2865 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002866 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 smb_buffer_response->WordCount));
2868 rc = -EIO;
2869 }
2870
2871 if (smb_buffer)
2872 cifs_buf_release(smb_buffer);
2873
2874 return rc;
2875}
2876static int
2877CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2878 char *ntlm_session_key, int ntlmv2_flag,
2879 const struct nls_table *nls_codepage)
2880{
2881 struct smb_hdr *smb_buffer;
2882 struct smb_hdr *smb_buffer_response;
2883 SESSION_SETUP_ANDX *pSMB;
2884 SESSION_SETUP_ANDX *pSMBr;
2885 char *bcc_ptr;
2886 char *user;
2887 char *domain;
2888 int rc = 0;
2889 int remaining_words = 0;
2890 int bytes_returned = 0;
2891 int len;
2892 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2893 PAUTHENTICATE_MESSAGE SecurityBlob;
2894 __u32 negotiate_flags, capabilities;
2895 __u16 count;
2896
2897 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002898 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 return -EINVAL;
2900 user = ses->userName;
2901 domain = ses->domainName;
2902 smb_buffer = cifs_buf_get();
2903 if (smb_buffer == NULL) {
2904 return -ENOMEM;
2905 }
2906 smb_buffer_response = smb_buffer;
2907 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2908 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2909
2910 /* send SMBsessionSetup here */
2911 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2912 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002913
2914 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2916 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2917 pSMB->req.AndXCommand = 0xFF;
2918 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2919 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2920
2921 pSMB->req.hdr.Uid = ses->Suid;
2922
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002923 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2925
2926 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2927 CAP_EXTENDED_SECURITY;
2928 if (ses->capabilities & CAP_UNICODE) {
2929 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2930 capabilities |= CAP_UNICODE;
2931 }
2932 if (ses->capabilities & CAP_STATUS32) {
2933 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2934 capabilities |= CAP_STATUS32;
2935 }
2936 if (ses->capabilities & CAP_DFS) {
2937 smb_buffer->Flags2 |= SMBFLG2_DFS;
2938 capabilities |= CAP_DFS;
2939 }
2940 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2941
2942 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2943 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2944 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2945 SecurityBlob->MessageType = NtLmAuthenticate;
2946 bcc_ptr += SecurityBlobLength;
Steve French50c2f752007-07-13 00:33:32 +00002947 negotiate_flags =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2949 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2950 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002951 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002953 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2955
2956/* setup pointers to domain name and workstation name */
2957
2958 SecurityBlob->WorkstationName.Buffer = 0;
2959 SecurityBlob->WorkstationName.Length = 0;
2960 SecurityBlob->WorkstationName.MaximumLength = 0;
2961 SecurityBlob->SessionKey.Length = 0;
2962 SecurityBlob->SessionKey.MaximumLength = 0;
2963 SecurityBlob->SessionKey.Buffer = 0;
2964
2965 SecurityBlob->LmChallengeResponse.Length = 0;
2966 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2967 SecurityBlob->LmChallengeResponse.Buffer = 0;
2968
2969 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002970 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002972 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2973 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 SecurityBlob->NtChallengeResponse.Buffer =
2975 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002976 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2977 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
2979 if (ses->capabilities & CAP_UNICODE) {
2980 if (domain == NULL) {
2981 SecurityBlob->DomainName.Buffer = 0;
2982 SecurityBlob->DomainName.Length = 0;
2983 SecurityBlob->DomainName.MaximumLength = 0;
2984 } else {
Steve French77159b42007-08-31 01:10:17 +00002985 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00002987 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00002989 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 SecurityBlob->DomainName.Buffer =
2991 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00002992 bcc_ptr += ln;
2993 SecurityBlobLength += ln;
2994 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 }
2996 if (user == NULL) {
2997 SecurityBlob->UserName.Buffer = 0;
2998 SecurityBlob->UserName.Length = 0;
2999 SecurityBlob->UserName.MaximumLength = 0;
3000 } else {
Steve French77159b42007-08-31 01:10:17 +00003001 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003003 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003005 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 SecurityBlob->UserName.Buffer =
3007 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003008 bcc_ptr += ln;
3009 SecurityBlobLength += ln;
3010 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 }
3012
Steve French63135e02007-07-17 17:34:02 +00003013 /* SecurityBlob->WorkstationName.Length =
3014 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003016 SecurityBlob->WorkstationName.MaximumLength =
3017 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3018 SecurityBlob->WorkstationName.Buffer =
3019 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 bcc_ptr += SecurityBlob->WorkstationName.Length;
3021 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003022 SecurityBlob->WorkstationName.Length =
3023 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
3025 if ((long) bcc_ptr % 2) {
3026 *bcc_ptr = 0;
3027 bcc_ptr++;
3028 }
3029 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003030 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 32, nls_codepage);
3032 bcc_ptr += 2 * bytes_returned;
3033 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003034 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 nls_codepage);
3036 bcc_ptr += 2 * bytes_returned;
3037 bcc_ptr += 2; /* null term version string */
3038 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003039 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 64, nls_codepage);
3041 bcc_ptr += 2 * bytes_returned;
3042 *(bcc_ptr + 1) = 0;
3043 *(bcc_ptr + 2) = 0;
3044 bcc_ptr += 2; /* null terminate network opsys string */
3045 *(bcc_ptr + 1) = 0;
3046 *(bcc_ptr + 2) = 0;
3047 bcc_ptr += 2; /* null domain */
3048 } else { /* ASCII */
3049 if (domain == NULL) {
3050 SecurityBlob->DomainName.Buffer = 0;
3051 SecurityBlob->DomainName.Length = 0;
3052 SecurityBlob->DomainName.MaximumLength = 0;
3053 } else {
Steve French77159b42007-08-31 01:10:17 +00003054 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3056 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003057 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003059 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 SecurityBlob->DomainName.Buffer =
3061 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003062 bcc_ptr += ln;
3063 SecurityBlobLength += ln;
3064 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 }
3066 if (user == NULL) {
3067 SecurityBlob->UserName.Buffer = 0;
3068 SecurityBlob->UserName.Length = 0;
3069 SecurityBlob->UserName.MaximumLength = 0;
3070 } else {
Steve French77159b42007-08-31 01:10:17 +00003071 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003073 ln = strnlen(user, 64);
3074 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003076 cpu_to_le32(SecurityBlobLength);
3077 bcc_ptr += ln;
3078 SecurityBlobLength += ln;
3079 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 }
3081 /* BB fill in our workstation name if known BB */
3082
3083 strcpy(bcc_ptr, "Linux version ");
3084 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003085 strcpy(bcc_ptr, utsname()->release);
3086 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3088 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3089 bcc_ptr++; /* null domain */
3090 *bcc_ptr = 0;
3091 }
3092 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3093 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3094 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3095 smb_buffer->smb_buf_length += count;
3096 pSMB->req.ByteCount = cpu_to_le16(count);
3097
3098 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3099 &bytes_returned, 1);
3100 if (rc) {
3101/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3102 } else if ((smb_buffer_response->WordCount == 3)
3103 || (smb_buffer_response->WordCount == 4)) {
3104 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3105 __u16 blob_len =
3106 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3107 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003108 cFYI(1, (" Guest login")); /* BB Should we set anything
3109 in SesInfo struct ? */
3110/* if (SecurityBlob2->MessageType != NtLm??) {
3111 cFYI("Unexpected message type on auth response is %d"));
3112 } */
3113
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 if (ses) {
3115 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003116 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003118 /* UID left in wire format */
3119 ses->Suid = smb_buffer_response->Uid;
3120 bcc_ptr = pByteArea(smb_buffer_response);
3121 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 if ((pSMBr->resp.hdr.WordCount == 3)
3123 || ((pSMBr->resp.hdr.WordCount == 4)
3124 && (blob_len <
3125 pSMBr->resp.ByteCount))) {
3126 if (pSMBr->resp.hdr.WordCount == 4) {
3127 bcc_ptr +=
3128 blob_len;
3129 cFYI(1,
3130 ("Security Blob Length %d ",
3131 blob_len));
3132 }
3133
3134 cFYI(1,
3135 ("NTLMSSP response to Authenticate "));
3136
3137 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3138 if ((long) (bcc_ptr) % 2) {
3139 remaining_words =
3140 (BCC(smb_buffer_response)
3141 - 1) / 2;
3142 bcc_ptr++; /* Unicode strings must be word aligned */
3143 } else {
3144 remaining_words = BCC(smb_buffer_response) / 2;
3145 }
Steve French77159b42007-08-31 01:10:17 +00003146 len = UniStrnlen((wchar_t *) bcc_ptr,
3147 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148/* We look for obvious messed up bcc or strings in response so we do not go off
3149 the end since (at least) WIN2K and Windows XP have a major bug in not null
3150 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003151 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003152 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003154 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003156 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 bcc_ptr, len,
3158 nls_codepage);
3159 bcc_ptr += 2 * (len + 1);
3160 remaining_words -= len + 1;
3161 ses->serverOS[2 * len] = 0;
3162 ses->serverOS[1 + (2 * len)] = 0;
3163 if (remaining_words > 0) {
3164 len = UniStrnlen((wchar_t *)
3165 bcc_ptr,
3166 remaining_words
3167 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003168 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003170 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 GFP_KERNEL);
3172 cifs_strfromUCS_le(ses->
3173 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003174 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 bcc_ptr,
3176 len,
3177 nls_codepage);
3178 bcc_ptr += 2 * (len + 1);
3179 ses->serverNOS[2 * len] = 0;
3180 ses->serverNOS[1+(2*len)] = 0;
3181 remaining_words -= len + 1;
3182 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003183 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003185 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003186 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003188 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 (len +
3190 1),
3191 GFP_KERNEL);
3192 cifs_strfromUCS_le
3193 (ses->
3194 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003195 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 bcc_ptr, len,
3197 nls_codepage);
3198 bcc_ptr +=
3199 2 * (len + 1);
3200 ses->
3201 serverDomain[2
3202 * len]
3203 = 0;
3204 ses->
3205 serverDomain[1
3206 +
3207 (2
3208 *
3209 len)]
3210 = 0;
3211 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003212 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003213 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003214 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003215 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003218 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003219 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003220 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003221 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003222 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 }
3224 } else { /* ASCII */
3225 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003226 if (((long) bcc_ptr + len) -
3227 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003228 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003229 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003230 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003231 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 strncpy(ses->serverOS,bcc_ptr, len);
3233
3234 bcc_ptr += len;
3235 bcc_ptr[0] = 0; /* null terminate the string */
3236 bcc_ptr++;
3237
3238 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003239 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003240 ses->serverNOS = kzalloc(len+1,
3241 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003242 strncpy(ses->serverNOS,
3243 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 bcc_ptr += len;
3245 bcc_ptr[0] = 0;
3246 bcc_ptr++;
3247
3248 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003249 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003250 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003251 ses->serverDomain =
3252 kzalloc(len+1,
3253 GFP_KERNEL);
3254 strncpy(ses->serverDomain,
3255 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 bcc_ptr += len;
3257 bcc_ptr[0] = 0;
3258 bcc_ptr++;
3259 } else
3260 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003261 ("field of length %d "
3262 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 len));
3264 }
3265 } else {
3266 cERROR(1,
Steve French63135e02007-07-17 17:34:02 +00003267 (" Security Blob extends beyond end "
3268 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 }
3270 } else {
3271 cERROR(1, ("No session structure passed in."));
3272 }
3273 } else {
3274 cERROR(1,
3275 (" Invalid Word count %d: ",
3276 smb_buffer_response->WordCount));
3277 rc = -EIO;
3278 }
3279
3280 if (smb_buffer)
3281 cifs_buf_release(smb_buffer);
3282
3283 return rc;
3284}
3285
3286int
3287CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3288 const char *tree, struct cifsTconInfo *tcon,
3289 const struct nls_table *nls_codepage)
3290{
3291 struct smb_hdr *smb_buffer;
3292 struct smb_hdr *smb_buffer_response;
3293 TCONX_REQ *pSMB;
3294 TCONX_RSP *pSMBr;
3295 unsigned char *bcc_ptr;
3296 int rc = 0;
3297 int length;
3298 __u16 count;
3299
3300 if (ses == NULL)
3301 return -EIO;
3302
3303 smb_buffer = cifs_buf_get();
3304 if (smb_buffer == NULL) {
3305 return -ENOMEM;
3306 }
3307 smb_buffer_response = smb_buffer;
3308
3309 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3310 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003311
3312 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 smb_buffer->Uid = ses->Suid;
3314 pSMB = (TCONX_REQ *) smb_buffer;
3315 pSMBr = (TCONX_RSP *) smb_buffer_response;
3316
3317 pSMB->AndXCommand = 0xFF;
3318 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003320 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003321 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003322 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003323 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003324 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003325 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003326 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003327 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3328 specified as required (when that support is added to
3329 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003330 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003331 by Samba (not sure whether other servers allow
3332 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003333#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003334 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003335 (ses->server->secType == LANMAN))
3336 calc_lanman_hash(ses, bcc_ptr);
3337 else
3338#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003339 SMBNTencrypt(ses->password,
3340 ses->server->cryptKey,
3341 bcc_ptr);
3342
Steve French7c7b25b2006-06-01 19:20:10 +00003343 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003344 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003345 /* must align unicode strings */
3346 *bcc_ptr = 0; /* null byte password */
3347 bcc_ptr++;
3348 }
Steve Frencheeac8042006-01-13 21:34:58 -08003349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350
Steve French50c2f752007-07-13 00:33:32 +00003351 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003352 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3354
3355 if (ses->capabilities & CAP_STATUS32) {
3356 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3357 }
3358 if (ses->capabilities & CAP_DFS) {
3359 smb_buffer->Flags2 |= SMBFLG2_DFS;
3360 }
3361 if (ses->capabilities & CAP_UNICODE) {
3362 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3363 length =
Steve French50c2f752007-07-13 00:33:32 +00003364 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3365 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003366 (/* server len*/ + 256 /* share len */), nls_codepage);
3367 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 bcc_ptr += 2; /* skip trailing null */
3369 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 strcpy(bcc_ptr, tree);
3371 bcc_ptr += strlen(tree) + 1;
3372 }
3373 strcpy(bcc_ptr, "?????");
3374 bcc_ptr += strlen("?????");
3375 bcc_ptr += 1;
3376 count = bcc_ptr - &pSMB->Password[0];
3377 pSMB->hdr.smb_buf_length += count;
3378 pSMB->ByteCount = cpu_to_le16(count);
3379
3380 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3381
3382 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3383 /* above now done in SendReceive */
3384 if ((rc == 0) && (tcon != NULL)) {
3385 tcon->tidStatus = CifsGood;
3386 tcon->tid = smb_buffer_response->Tid;
3387 bcc_ptr = pByteArea(smb_buffer_response);
3388 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003389 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003390 if (length == 3) {
3391 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3392 (bcc_ptr[2] == 'C')) {
3393 cFYI(1, ("IPC connection"));
3394 tcon->ipc = 1;
3395 }
3396 } else if (length == 2) {
3397 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3398 /* the most common case */
3399 cFYI(1, ("disk share connection"));
3400 }
3401 }
Steve French50c2f752007-07-13 00:33:32 +00003402 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3404 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3405 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3406 if ((bcc_ptr + (2 * length)) -
3407 pByteArea(smb_buffer_response) <=
3408 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003409 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003411 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003412 if (tcon->nativeFileSystem)
3413 cifs_strfromUCS_le(
3414 tcon->nativeFileSystem,
3415 (__le16 *) bcc_ptr,
3416 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 bcc_ptr += 2 * length;
3418 bcc_ptr[0] = 0; /* null terminate the string */
3419 bcc_ptr[1] = 0;
3420 bcc_ptr += 2;
3421 }
Steve French50c2f752007-07-13 00:33:32 +00003422 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 } else {
3424 length = strnlen(bcc_ptr, 1024);
3425 if ((bcc_ptr + length) -
3426 pByteArea(smb_buffer_response) <=
3427 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003428 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003430 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003431 if (tcon->nativeFileSystem)
3432 strncpy(tcon->nativeFileSystem, bcc_ptr,
3433 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 }
Steve French50c2f752007-07-13 00:33:32 +00003435 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003437 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003438 (smb_buffer_response->WordCount == 7))
3439 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003440 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3441 else
3442 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3444 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003445 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 ses->ipc_tid = smb_buffer_response->Tid;
3447 }
3448
3449 if (smb_buffer)
3450 cifs_buf_release(smb_buffer);
3451 return rc;
3452}
3453
3454int
3455cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3456{
3457 int rc = 0;
3458 int xid;
3459 struct cifsSesInfo *ses = NULL;
3460 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003461 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462
3463 xid = GetXid();
3464
3465 if (cifs_sb->tcon) {
3466 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3467 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3468 if (rc == -EBUSY) {
3469 FreeXid(xid);
3470 return 0;
3471 }
3472 tconInfoFree(cifs_sb->tcon);
3473 if ((ses) && (ses->server)) {
3474 /* save off task so we do not refer to ses later */
3475 cifsd_task = ses->server->tsk;
3476 cFYI(1, ("About to do SMBLogoff "));
3477 rc = CIFSSMBLogoff(xid, ses);
3478 if (rc == -EBUSY) {
3479 FreeXid(xid);
3480 return 0;
3481 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003482 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003483 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003484 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003485 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 rc = 0;
3488 } /* else - we have an smb session
3489 left on this socket do not kill cifsd */
3490 } else
3491 cFYI(1, ("No session or bad tcon"));
3492 }
Steve French50c2f752007-07-13 00:33:32 +00003493
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003495 tmp = cifs_sb->prepath;
3496 cifs_sb->prepathlen = 0;
3497 cifs_sb->prepath = NULL;
3498 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003499 if (ses)
3500 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 if (ses)
3502 sesInfoFree(ses);
3503
3504 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003505 return rc; /* BB check if we should always return zero here */
3506}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507
3508int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003509 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510{
3511 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003512 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003514 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515
3516 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003517 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003519 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003521 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 rc = -EHOSTDOWN;
3523 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003524 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003526 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 pSesInfo->server->tcpStatus = CifsGood;
3528 else
3529 rc = -EHOSTDOWN;
3530 spin_unlock(&GlobalMid_Lock);
3531
3532 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003533 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 }
3535 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003536 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003538 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003540 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003541 cFYI(1,
3542 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 pSesInfo->server->secMode,
3544 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003545 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003546 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003547 rc = CIFS_SessSetup(xid, pSesInfo,
3548 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003549 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003550 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003551 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003553 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 } else if (extended_security
3555 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3556 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003557 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3559 pSesInfo,
3560 &ntlmv2_flag,
3561 nls_info);
3562 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003563 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003564 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003565 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003566 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 nls_info)) {
3568 rc = -ENOMEM;
3569 goto ss_err_exit;
3570 } else
3571 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003572 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003573 CalcNTLMv2_response(pSesInfo,
3574 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003575 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003576 cifs_calculate_ntlmv2_mac_key(
3577 pSesInfo->server->mac_signing_key,
3578 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 kfree(v2_response);
3580 /* BB Put dummy sig in SessSetup PDU? */
3581 } else {
3582 rc = -ENOMEM;
3583 goto ss_err_exit;
3584 }
3585
3586 } else {
3587 SMBNTencrypt(pSesInfo->password,
3588 pSesInfo->server->cryptKey,
3589 ntlm_session_key);
3590
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003591 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003592 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003593 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003594 ntlm_session_key,
3595 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 }
3597 /* for better security the weaker lanman hash not sent
3598 in AuthSessSetup so we no longer calculate it */
3599
3600 rc = CIFSNTLMSSPAuthSessSetup(xid,
3601 pSesInfo,
3602 ntlm_session_key,
3603 ntlmv2_flag,
3604 nls_info);
3605 }
3606 } else { /* old style NTLM 0.12 session setup */
3607 SMBNTencrypt(pSesInfo->password,
3608 pSesInfo->server->cryptKey,
3609 ntlm_session_key);
3610
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003611 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003612 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003613 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003614 ntlm_session_key, pSesInfo->password);
3615
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 rc = CIFSSessSetup(xid, pSesInfo,
3617 ntlm_session_key, nls_info);
3618 }
3619 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003620 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 } else {
Steve French467a8f82007-06-27 22:41:32 +00003622 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 pSesInfo->status = CifsGood;
3624 }
3625 }
3626ss_err_exit:
3627 return rc;
3628}
3629