blob: 9d6d9a09d97384731fe335547b0cce0349ffa08c [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 Frenchd7245c22005-07-14 18:25:12 -050088 unsigned sfu_emul:1;
Steve Frenchbf820672005-12-01 22:32:42 -080089 unsigned nullauth:1; /* attempt to authenticate with null user */
Steve Frenchc46fa8a2005-08-18 20:49:57 -070090 unsigned nocase; /* request case insensitive filenames */
91 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 unsigned int rsize;
93 unsigned int wsize;
94 unsigned int sockopt;
95 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000096 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097};
98
Steve Frenchfb8c4b12007-07-10 01:16:18 +000099static int ipv4_connect(struct sockaddr_in *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 struct socket **csocket,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000101 char *netb_name,
102 char *server_netb_name);
103static int ipv6_connect(struct sockaddr_in6 *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 struct socket **csocket);
105
106
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000107 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000109 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 * mark tcp session as reconnecting so temporarily locked
111 * mark all smb sessions as reconnecting for tcp session
112 * reconnect tcp session
113 * wake up waiters on reconnection? - (not needed currently)
114 */
115
Steve French2cd646a2006-09-28 19:43:08 +0000116static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117cifs_reconnect(struct TCP_Server_Info *server)
118{
119 int rc = 0;
120 struct list_head *tmp;
121 struct cifsSesInfo *ses;
122 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000123 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000126 if ( kthread_should_stop() ) {
127 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 next time through the loop */
129 spin_unlock(&GlobalMid_Lock);
130 return rc;
131 } else
132 server->tcpStatus = CifsNeedReconnect;
133 spin_unlock(&GlobalMid_Lock);
134 server->maxBuf = 0;
135
Steve Frenche4eb2952005-04-28 22:41:09 -0700136 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138 /* before reconnecting the tcp session, mark the smb session (uid)
139 and the tid bad so they are not used until reconnected */
140 read_lock(&GlobalSMBSeslock);
141 list_for_each(tmp, &GlobalSMBSessionList) {
142 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
143 if (ses->server) {
144 if (ses->server == server) {
145 ses->status = CifsNeedReconnect;
146 ses->ipc_tid = 0;
147 }
148 }
149 /* else tcp and smb sessions need reconnection */
150 }
151 list_for_each(tmp, &GlobalTreeConnectionList) {
152 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000153 if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 tcon->tidStatus = CifsNeedReconnect;
155 }
156 }
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 Frenchfb8c4b12007-07-10 01:16:18 +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 Frenchfb8c4b12007-07-10 01:16:18 +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)) {
281 cFYI(1, ("total data sizes 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 Frenchfb8c4b12007-07-10 01:16:18 +0000360 if (length > 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 mempool_resize(cifs_req_poolp,
362 length + cifs_min_rcv,
363 GFP_KERNEL);
364 }
365
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000366 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700367 if (try_to_freeze())
368 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700369 if (bigbuf == NULL) {
370 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000371 if (!bigbuf) {
372 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700373 msleep(3000);
374 /* retry will check if exiting */
375 continue;
376 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000377 } else if (isLargeBuf) {
378 /* we are reusing a dirty large buf, clear its start */
Steve Frenchb8643e12005-04-28 22:41:07 -0700379 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700381
382 if (smallbuf == NULL) {
383 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000384 if (!smallbuf) {
385 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700386 msleep(1000);
387 /* retry will check if exiting */
388 continue;
389 }
390 /* beginning of smb buffer is cleared in our buf_get */
391 } else /* if existing small buf clear beginning */
392 memset(smallbuf, 0, sizeof (struct smb_hdr));
393
394 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700395 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700396 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 iov.iov_base = smb_buffer;
398 iov.iov_len = 4;
399 smb_msg.msg_control = NULL;
400 smb_msg.msg_controllen = 0;
401 length =
402 kernel_recvmsg(csocket, &smb_msg,
403 &iov, 1, 4, 0 /* BB see socket.h flags */);
404
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000405 if ( kthread_should_stop() ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 break;
407 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000408 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000410 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 csocket = server->ssocket;
412 continue;
413 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700414 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 allowing socket to clear and app threads to set
416 tcpStatus CifsNeedReconnect if server hung */
417 continue;
418 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000419 if (server->tcpStatus == CifsNew) {
420 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700421 /* some servers kill the TCP session rather than
422 returning an SMB negprot error, in which
423 case reconnecting here is not going to help,
424 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 break;
426 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000427 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000428 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 break;
430 }
Steve French467a8f82007-06-27 22:41:32 +0000431 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700432 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 cifs_reconnect(server);
434 csocket = server->ssocket;
435 wake_up(&server->response_q);
436 continue;
Steve French46810cb2005-04-28 22:41:09 -0700437 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700439 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 length));
441 cifs_reconnect(server);
442 csocket = server->ssocket;
443 wake_up(&server->response_q);
444 continue;
445 }
Steve French67010fb2005-04-28 22:41:09 -0700446
Steve French70ca7342005-09-22 16:32:06 -0700447 /* The right amount was read from socket - 4 bytes */
448 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700449
Steve French70ca7342005-09-22 16:32:06 -0700450 /* the first byte big endian of the length field,
451 is actually not part of the length but the type
452 with the most common, zero, as regular data */
453 temp = *((char *) smb_buffer);
454
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000455 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700456 but we convert it here so it is always manipulated
457 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700458 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700459 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700460
Steve French467a8f82007-06-27 22:41:32 +0000461 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700462
463 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000464 continue;
Steve French70ca7342005-09-22 16:32:06 -0700465 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000466 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700467 continue;
Steve French70ca7342005-09-22 16:32:06 -0700468 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000469 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700470 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000471 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700472 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 if (server->tcpStatus == CifsNew) {
474 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700475 ret of smb negprot error) reconnecting
476 not going to help, ret error to mount */
477 break;
478 } else {
479 /* give server a second to
480 clean up before reconnect attempt */
481 msleep(1000);
482 /* always try 445 first on reconnect
483 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000484 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700485 since we do not begin with RFC1001
486 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000487 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700488 htons(CIFS_PORT);
489 cifs_reconnect(server);
490 csocket = server->ssocket;
491 wake_up(&server->response_q);
492 continue;
493 }
Steve French70ca7342005-09-22 16:32:06 -0700494 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000495 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700496 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
497 length);
Steve French46810cb2005-04-28 22:41:09 -0700498 cifs_reconnect(server);
499 csocket = server->ssocket;
500 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700501 }
502
503 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000504 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700505 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700506 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700507 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700508 cifs_reconnect(server);
509 csocket = server->ssocket;
510 wake_up(&server->response_q);
511 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000512 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700513
514 /* else length ok */
515 reconnect = 0;
516
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000517 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700518 isLargeBuf = TRUE;
519 memcpy(bigbuf, smallbuf, 4);
520 smb_buffer = bigbuf;
521 }
522 length = 0;
523 iov.iov_base = 4 + (char *)smb_buffer;
524 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000525 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700526 total_read += length) {
527 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
528 pdu_length - total_read, 0);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000529 if ( kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700530 (length == -EINTR)) {
531 /* then will exit */
532 reconnect = 2;
533 break;
534 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700535 cifs_reconnect(server);
536 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000537 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700538 /* Now we will reread sock */
539 reconnect = 1;
540 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000541 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700542 (length == -EAGAIN)) {
543 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000544 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700545 threads to set tcpStatus
546 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700547 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000549 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700550 pdu_length - total_read));
551 cifs_reconnect(server);
552 csocket = server->ssocket;
553 reconnect = 1;
554 break;
Steve French46810cb2005-04-28 22:41:09 -0700555 }
556 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000557 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000559 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700560 continue;
561
562 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000563
Steve Frenche4eb2952005-04-28 22:41:09 -0700564
565 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000566 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700567 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700568 continue;
569 }
570
571
572 task_to_wake = NULL;
573 spin_lock(&GlobalMid_Lock);
574 list_for_each(tmp, &server->pending_mid_q) {
575 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
576
Steve French50c2f752007-07-13 00:33:32 +0000577 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
579 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000580 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700582 isMultiRsp = TRUE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000583 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000585 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000587 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700588 break;
589 } else {
590 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000591 mid_entry->multiEnd = 1;
Steve French50c2f752007-07-13 00:33:32 +0000592 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700593 }
594 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000595 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 cERROR(1,("1st trans2 resp needs bigbuf"));
597 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000598 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700600 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700601 mid_entry->resp_buf =
602 smb_buffer;
603 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700604 bigbuf = NULL;
605 }
606 }
607 break;
Steve French50c2f752007-07-13 00:33:32 +0000608 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700609 mid_entry->resp_buf = smb_buffer;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000610 if (isLargeBuf)
Steve Frenche4eb2952005-04-28 22:41:09 -0700611 mid_entry->largeBuf = 1;
612 else
613 mid_entry->largeBuf = 0;
614multi_t2_fnd:
615 task_to_wake = mid_entry->tsk;
616 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700617#ifdef CONFIG_CIFS_STATS2
618 mid_entry->when_received = jiffies;
619#endif
Steve French3a5ff612006-07-14 22:37:11 +0000620 /* so we do not time out requests to server
621 which is still responding (since server could
622 be busy but not dead) */
623 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700624 break;
625 }
626 }
627 spin_unlock(&GlobalMid_Lock);
628 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700629 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000630 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700631 /* smb buffer will be freed by user thread */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000632 if (isLargeBuf) {
Steve Frenchcd634992005-04-28 22:41:10 -0700633 bigbuf = NULL;
634 } else
635 smallbuf = NULL;
636 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700637 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000638 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve French50c2f752007-07-13 00:33:32 +0000639 && (isMultiRsp == FALSE)) {
640 cERROR(1, ("No task to wake, unknown frame received! "
641 "NumMids %d", midCount.counter));
642 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700643 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000644#ifdef CONFIG_CIFS_DEBUG2
645 cifs_dump_detail(smb_buffer);
646 cifs_dump_mids(server);
647#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000648
Steve Frenche4eb2952005-04-28 22:41:09 -0700649 }
650 } /* end while !EXITING */
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 spin_lock(&GlobalMid_Lock);
653 server->tcpStatus = CifsExiting;
654 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700655 /* check if we have blocked requests that need to free */
656 /* Note that cifs_max_pending is normally 50, but
657 can be set at module install time to as little as two */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000658 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700659 atomic_set(&server->inFlight, cifs_max_pending - 1);
660 /* We do not want to set the max_pending too low or we
661 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000663 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700665 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 to the same server - they now will see the session is in exit state
667 and get out of SendReceive. */
668 wake_up_all(&server->request_q);
669 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700670 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000671
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000672 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 sock_release(csocket);
674 server->ssocket = NULL;
675 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700676 /* buffer usuallly freed in free_mid - need to free it here on exit */
677 if (bigbuf != NULL)
678 cifs_buf_release(bigbuf);
679 if (smallbuf != NULL)
680 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 read_lock(&GlobalSMBSeslock);
683 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700684 /* loop through server session structures attached to this and
685 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 list_for_each(tmp, &GlobalSMBSessionList) {
687 ses =
688 list_entry(tmp, struct cifsSesInfo,
689 cifsSessionList);
690 if (ses->server == server) {
691 ses->status = CifsExiting;
692 ses->server = NULL;
693 }
694 }
695 read_unlock(&GlobalSMBSeslock);
696 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700697 /* although we can not zero the server struct pointer yet,
698 since there are active requests which may depnd on them,
699 mark the corresponding SMB sessions as exiting too */
700 list_for_each(tmp, &GlobalSMBSessionList) {
701 ses = list_entry(tmp, struct cifsSesInfo,
702 cifsSessionList);
703 if (ses->server == server) {
704 ses->status = CifsExiting;
705 }
706 }
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 spin_lock(&GlobalMid_Lock);
709 list_for_each(tmp, &server->pending_mid_q) {
710 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
711 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000712 cFYI(1, ("Clearing Mid 0x%x - waking up ",
713 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 task_to_wake = mid_entry->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000715 if (task_to_wake) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 wake_up_process(task_to_wake);
717 }
718 }
719 }
720 spin_unlock(&GlobalMid_Lock);
721 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700723 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725
Steve Frenchf1914012005-08-18 09:37:34 -0700726 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000727 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700729 /* due to delays on oplock break requests, we need
730 to wait at least 45 seconds before giving up
731 on a request getting a response and going ahead
732 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700734 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /* if threads still have not exited they are probably never
736 coming home not much else we can do but free the memory */
737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 write_lock(&GlobalSMBSeslock);
740 atomic_dec(&tcpSesAllocCount);
741 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700742
743 /* last chance to mark ses pointers invalid
744 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000745 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700746 kernel thread explicitly this might happen) */
747 list_for_each(tmp, &GlobalSMBSessionList) {
748 ses = list_entry(tmp, struct cifsSesInfo,
749 cifsSessionList);
750 if (ses->server == server) {
751 ses->server = NULL;
752 }
753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700755
756 kfree(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000757 if (length > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 mempool_resize(cifs_req_poolp,
759 length + cifs_min_rcv,
760 GFP_KERNEL);
761 }
Steve French50c2f752007-07-13 00:33:32 +0000762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return 0;
764}
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766static int
Steve French50c2f752007-07-13 00:33:32 +0000767cifs_parse_mount_options(char *options, const char *devname,
768 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
770 char *value;
771 char *data;
772 unsigned int temp_len, i, j;
773 char separator[2];
774
775 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000776 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Linus Torvalds12e36b22006-10-13 08:09:29 -0700778 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000779 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000780 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700781 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000782 int n = strnlen(nodename, 15);
783 memset(vol->source_rfc1001_name, 0x20, 15);
784 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000785 /* does not have to be perfect mapping since field is
786 informational, only used for servers that do not support
787 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700788 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700792 /* null target name indicates to use *SMBSERVR default called name
793 if we end up sending RFC1001 session initialize */
794 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 vol->linux_uid = current->uid; /* current->euid instead? */
796 vol->linux_gid = current->gid;
797 vol->dir_mode = S_IRWXUGO;
798 /* 2767 perms indicate mandatory locking support */
799 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
800
801 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
802 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700803 /* default is always to request posix paths. */
804 vol->posix_paths = 1;
805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 if (!options)
807 return 1;
808
Steve French50c2f752007-07-13 00:33:32 +0000809 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000810 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 separator[0] = options[4];
812 options += 5;
813 } else {
Steve French467a8f82007-06-27 22:41:32 +0000814 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
816 }
Steve French50c2f752007-07-13 00:33:32 +0000817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 while ((data = strsep(&options, separator)) != NULL) {
819 if (!*data)
820 continue;
821 if ((value = strchr(data, '=')) != NULL)
822 *value++ = '\0';
823
Steve French50c2f752007-07-13 00:33:32 +0000824 /* Have to parse this before we parse for "user" */
825 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000827 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 vol->no_xattr = 1;
829 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000830 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 printk(KERN_WARNING
832 "CIFS: invalid or missing username\n");
833 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000834 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000835 /* null user, ie anonymous, authentication */
836 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
838 if (strnlen(value, 200) < 200) {
839 vol->username = value;
840 } else {
841 printk(KERN_WARNING "CIFS: username too long\n");
842 return 1;
843 }
844 } else if (strnicmp(data, "pass", 4) == 0) {
845 if (!value) {
846 vol->password = NULL;
847 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000848 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 /* check if string begins with double comma
850 since that would mean the password really
851 does start with a comma, and would not
852 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000853 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 vol->password = NULL;
855 continue;
856 }
857 }
858 temp_len = strlen(value);
859 /* removed password length check, NTLM passwords
860 can be arbitrarily long */
861
Steve French50c2f752007-07-13 00:33:32 +0000862 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 prematurely null terminated. Commas in password are
864 specified across the cifs mount interface by a double
865 comma ie ,, and a comma used as in other cases ie ','
866 as a parameter delimiter/separator is single and due
867 to the strsep above is temporarily zeroed. */
868
869 /* NB: password legally can have multiple commas and
870 the only illegal character in a password is null */
871
Steve French50c2f752007-07-13 00:33:32 +0000872 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700873 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 /* reinsert comma */
875 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000876 temp_len += 2; /* move after second comma */
877 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000879 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700880 separator[0]) {
881 /* skip second comma */
882 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000883 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 /* single comma indicating start
885 of next parm */
886 break;
887 }
888 }
889 temp_len++;
890 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000891 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 options = NULL;
893 } else {
894 value[temp_len] = 0;
895 /* point option to start of next parm */
896 options = value + temp_len + 1;
897 }
Steve French50c2f752007-07-13 00:33:32 +0000898 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 double commas to singles. Note that this ends up
900 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700901 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000902 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000903 printk(KERN_WARNING "CIFS: no memory "
904 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700905 return 1;
906 }
Steve French50c2f752007-07-13 00:33:32 +0000907 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000909 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700910 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 /* skip second comma */
912 i++;
913 }
914 }
915 vol->password[j] = 0;
916 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700917 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000918 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000919 printk(KERN_WARNING "CIFS: no memory "
920 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700921 return 1;
922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 strcpy(vol->password, value);
924 }
925 } else if (strnicmp(data, "ip", 2) == 0) {
926 if (!value || !*value) {
927 vol->UNCip = NULL;
928 } else if (strnlen(value, 35) < 35) {
929 vol->UNCip = value;
930 } else {
Steve French50c2f752007-07-13 00:33:32 +0000931 printk(KERN_WARNING "CIFS: ip address "
932 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 return 1;
934 }
Steve French50c2f752007-07-13 00:33:32 +0000935 } else if (strnicmp(data, "sec", 3) == 0) {
936 if (!value || !*value) {
937 cERROR(1, ("no security value specified"));
938 continue;
939 } else if (strnicmp(value, "krb5i", 5) == 0) {
940 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000941 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800942 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000943 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
944 CIFSSEC_MAY_KRB5; */
945 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800946 return 1;
947 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000948 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800949 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000950 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000951 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800952 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000953 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800954 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000955 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000956 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800957 } else if (strnicmp(value, "ntlm", 4) == 0) {
958 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000959 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800960 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000961 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000962 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000963#ifdef CONFIG_CIFS_WEAK_PW_HASH
964 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000965 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000966#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800967 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000968 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000969 } else {
970 cERROR(1, ("bad security option: %s", value));
971 return 1;
972 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 } else if ((strnicmp(data, "unc", 3) == 0)
974 || (strnicmp(data, "target", 6) == 0)
975 || (strnicmp(data, "path", 4) == 0)) {
976 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +0000977 printk(KERN_WARNING "CIFS: invalid path to "
978 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return 1; /* needs_arg; */
980 }
981 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +0000982 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000983 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return 1;
Steve French50c2f752007-07-13 00:33:32 +0000985 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (strncmp(vol->UNC, "//", 2) == 0) {
987 vol->UNC[0] = '\\';
988 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +0000989 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +0000991 "CIFS: UNC Path does not begin "
992 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 return 1;
994 }
995 } else {
996 printk(KERN_WARNING "CIFS: UNC name too long\n");
997 return 1;
998 }
999 } else if ((strnicmp(data, "domain", 3) == 0)
1000 || (strnicmp(data, "workgroup", 5) == 0)) {
1001 if (!value || !*value) {
1002 printk(KERN_WARNING "CIFS: invalid domain name\n");
1003 return 1; /* needs_arg; */
1004 }
1005 /* BB are there cases in which a comma can be valid in
1006 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001007 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 vol->domainname = value;
1009 cFYI(1, ("Domain name set"));
1010 } else {
Steve French50c2f752007-07-13 00:33:32 +00001011 printk(KERN_WARNING "CIFS: domain name too "
1012 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 return 1;
1014 }
Steve French50c2f752007-07-13 00:33:32 +00001015 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1016 if (!value || !*value) {
1017 printk(KERN_WARNING
1018 "CIFS: invalid path prefix\n");
1019 return 1; /* needs_argument */
1020 }
1021 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001022 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001023 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001024 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1025 if (vol->prepath == NULL)
1026 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001027 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001028 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001029 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001030 } else
Steve French50c2f752007-07-13 00:33:32 +00001031 strcpy(vol->prepath, value);
1032 cFYI(1, ("prefix path %s", vol->prepath));
1033 } else {
1034 printk(KERN_WARNING "CIFS: prefix too long\n");
1035 return 1;
1036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 } else if (strnicmp(data, "iocharset", 9) == 0) {
1038 if (!value || !*value) {
1039 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
1040 return 1; /* needs_arg; */
1041 }
1042 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001043 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001045 /* if iocharset not set then load_nls_default
1046 is used by caller */
1047 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 } else {
1049 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
1050 return 1;
1051 }
1052 } else if (strnicmp(data, "uid", 3) == 0) {
1053 if (value && *value) {
1054 vol->linux_uid =
1055 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001056 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
1058 } else if (strnicmp(data, "gid", 3) == 0) {
1059 if (value && *value) {
1060 vol->linux_gid =
1061 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001062 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
1064 } else if (strnicmp(data, "file_mode", 4) == 0) {
1065 if (value && *value) {
1066 vol->file_mode =
1067 simple_strtoul(value, &value, 0);
1068 }
1069 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1070 if (value && *value) {
1071 vol->dir_mode =
1072 simple_strtoul(value, &value, 0);
1073 }
1074 } else if (strnicmp(data, "dirmode", 4) == 0) {
1075 if (value && *value) {
1076 vol->dir_mode =
1077 simple_strtoul(value, &value, 0);
1078 }
1079 } else if (strnicmp(data, "port", 4) == 0) {
1080 if (value && *value) {
1081 vol->port =
1082 simple_strtoul(value, &value, 0);
1083 }
1084 } else if (strnicmp(data, "rsize", 5) == 0) {
1085 if (value && *value) {
1086 vol->rsize =
1087 simple_strtoul(value, &value, 0);
1088 }
1089 } else if (strnicmp(data, "wsize", 5) == 0) {
1090 if (value && *value) {
1091 vol->wsize =
1092 simple_strtoul(value, &value, 0);
1093 }
1094 } else if (strnicmp(data, "sockopt", 5) == 0) {
1095 if (value && *value) {
1096 vol->sockopt =
1097 simple_strtoul(value, &value, 0);
1098 }
1099 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1100 if (!value || !*value || (*value == ' ')) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001101 cFYI(1, ("invalid (empty) netbiosname specified"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 } else {
Steve French50c2f752007-07-13 00:33:32 +00001103 memset(vol->source_rfc1001_name, 0x20, 15);
1104 for (i = 0; i < 15; i++) {
1105 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 valid in this workstation netbios name (and need
1107 special handling)? */
1108
1109 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001110 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 break;
Steve French50c2f752007-07-13 00:33:32 +00001112 else
1113 vol->source_rfc1001_name[i] =
1114 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 }
1116 /* The string has 16th byte zero still from
1117 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001118 if ((i == 15) && (value[i] != 0))
1119 printk(KERN_WARNING "CIFS: netbiosname"
1120 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001121 }
1122 } else if (strnicmp(data, "servern", 7) == 0) {
1123 /* servernetbiosname specified override *SMBSERVER */
1124 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001125 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001126 } else {
1127 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001128 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001129
Steve French50c2f752007-07-13 00:33:32 +00001130 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001131 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001132 valid in this workstation netbios name
1133 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001134
Steve French50c2f752007-07-13 00:33:32 +00001135 /* user or mount helper must uppercase
1136 the netbiosname */
1137 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001138 break;
1139 else
Steve French50c2f752007-07-13 00:33:32 +00001140 vol->target_rfc1001_name[i] =
1141 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001142 }
1143 /* The string has 16th byte zero still from
1144 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001145 if ((i == 15) && (value[i] != 0))
1146 printk(KERN_WARNING "CIFS: server net"
1147 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149 } else if (strnicmp(data, "credentials", 4) == 0) {
1150 /* ignore */
1151 } else if (strnicmp(data, "version", 3) == 0) {
1152 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001153 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 /* ignore */
1155 } else if (strnicmp(data, "rw", 2) == 0) {
1156 vol->rw = TRUE;
1157 } else if ((strnicmp(data, "suid", 4) == 0) ||
1158 (strnicmp(data, "nosuid", 6) == 0) ||
1159 (strnicmp(data, "exec", 4) == 0) ||
1160 (strnicmp(data, "noexec", 6) == 0) ||
1161 (strnicmp(data, "nodev", 5) == 0) ||
1162 (strnicmp(data, "noauto", 6) == 0) ||
1163 (strnicmp(data, "dev", 3) == 0)) {
1164 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001165 uses these opts to set flags, and the flags are read
1166 by the kernel vfs layer before we get here (ie
1167 before read super) so there is no point trying to
1168 parse these options again and set anything and it
1169 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 continue;
1171 } else if (strnicmp(data, "ro", 2) == 0) {
1172 vol->rw = FALSE;
1173 } else if (strnicmp(data, "hard", 4) == 0) {
1174 vol->retry = 1;
1175 } else if (strnicmp(data, "soft", 4) == 0) {
1176 vol->retry = 0;
1177 } else if (strnicmp(data, "perm", 4) == 0) {
1178 vol->noperm = 0;
1179 } else if (strnicmp(data, "noperm", 6) == 0) {
1180 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001181 } else if (strnicmp(data, "mapchars", 8) == 0) {
1182 vol->remap = 1;
1183 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1184 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001185 } else if (strnicmp(data, "sfu", 3) == 0) {
1186 vol->sfu_emul = 1;
1187 } else if (strnicmp(data, "nosfu", 5) == 0) {
1188 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001189 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1190 vol->posix_paths = 1;
1191 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1192 vol->posix_paths = 0;
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
1666
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001667 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001668 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001669
Steve French8af18972007-02-14 04:42:51 +00001670 /* check for reconnect case in which we do not
1671 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001672 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001673 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001674 originally at mount time */
1675 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1676 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1677 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1678 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French8af18972007-02-14 04:42:51 +00001679
Steve French50c2f752007-07-13 00:33:32 +00001680
1681
1682
Steve French8af18972007-02-14 04:42:51 +00001683 }
Steve French50c2f752007-07-13 00:33:32 +00001684
Steve French8af18972007-02-14 04:42:51 +00001685 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001686 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001687 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001688 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001689 cFYI(1, ("negotiated posix acl support"));
1690 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001691 sb->s_flags |= MS_POSIXACL;
1692 }
1693
Steve French75865f8c2007-06-24 18:30:48 +00001694 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001695 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001696 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001697 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001698 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001699 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001700 CIFS_MOUNT_POSIX_PATHS;
1701 }
Steve French50c2f752007-07-13 00:33:32 +00001702
Steve French984acfe2007-04-26 16:42:50 +00001703 /* We might be setting the path sep back to a different
1704 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001705 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001706 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001707 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001708
1709 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1710 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1711 CIFS_SB(sb)->rsize = 127 * 1024;
1712#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001713 cFYI(1, ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001714#endif
1715 }
1716 }
Steve French50c2f752007-07-13 00:33:32 +00001717
1718
1719 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001720#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001721 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001722 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001723 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001724 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001725 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001726 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001727 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001728 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001729 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001730 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001731 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001732 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001733 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001734 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001735#endif /* CIFS_DEBUG2 */
1736 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001737 cFYI(1, ("setting capabilities failed"));
Steve French8af18972007-02-14 04:42:51 +00001738 }
1739 }
1740}
1741
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742int
1743cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1744 char *mount_data, const char *devname)
1745{
1746 int rc = 0;
1747 int xid;
1748 int address_type = AF_INET;
1749 struct socket *csocket = NULL;
1750 struct sockaddr_in sin_server;
1751 struct sockaddr_in6 sin_server6;
1752 struct smb_vol volume_info;
1753 struct cifsSesInfo *pSesInfo = NULL;
1754 struct cifsSesInfo *existingCifsSes = NULL;
1755 struct cifsTconInfo *tcon = NULL;
1756 struct TCP_Server_Info *srvTcp = NULL;
1757
1758 xid = GetXid();
1759
1760/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001761
1762 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001764 kfree(volume_info.UNC);
1765 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001766 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 FreeXid(xid);
1768 return -EINVAL;
1769 }
1770
Jeff Layton8426c392007-05-05 03:27:49 +00001771 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001772 cFYI(1, ("null user"));
Jeff Layton8426c392007-05-05 03:27:49 +00001773 volume_info.username = NULL;
1774 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001776 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001778 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001779 /* In userspace mount helper we can get user name from alternate
1780 locations such as env variables and files on disk */
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
1788 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001789 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1790 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001792 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001794 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1795 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001796 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 address_type = AF_INET6;
1798 } else {
1799 address_type = AF_INET;
1800 }
Steve French50c2f752007-07-13 00:33:32 +00001801
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001802 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001804 kfree(volume_info.UNC);
1805 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001806 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 FreeXid(xid);
1808 return -EINVAL;
1809 }
1810
1811 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1812 /* success */
1813 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001814 } else if (volume_info.UNCip) {
1815 /* BB using ip addr as server name to connect to the
1816 DFS root below */
1817 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001818 kfree(volume_info.UNC);
1819 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001820 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 FreeXid(xid);
1822 return -EINVAL;
1823 } else /* which servers DFS root would we conect to */ {
1824 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001825 ("CIFS mount error: No UNC path (e.g. -o "
1826 "unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001827 kfree(volume_info.UNC);
1828 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001829 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 FreeXid(xid);
1831 return -EINVAL;
1832 }
1833
1834 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001835 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 cifs_sb->local_nls = load_nls_default();
1837 /* load_nls_default can not return null */
1838 } else {
1839 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001840 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001841 cERROR(1, ("CIFS mount error: iocharset %s not found",
1842 volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001843 kfree(volume_info.UNC);
1844 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001845 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 FreeXid(xid);
1847 return -ELIBACC;
1848 }
1849 }
1850
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001851 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1853 NULL /* no ipv6 addr */,
1854 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001855 else if (address_type == AF_INET6) {
1856 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1858 &sin_server6.sin6_addr,
1859 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001860 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001861 kfree(volume_info.UNC);
1862 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001863 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 FreeXid(xid);
1865 return -EINVAL;
1866 }
1867
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001869 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001871 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 sin_server.sin_port = htons(volume_info.port);
1873 else
1874 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001875 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001876 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001877 /* BB should we allow ipv6 on port 139? */
1878 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001879 rc = ipv6_connect(&sin_server6, &csocket);
1880 } else
1881 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001882 volume_info.source_rfc1001_name,
1883 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001885 cERROR(1, ("Error connecting to IPv4 socket. "
1886 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001887 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001889 kfree(volume_info.UNC);
1890 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001891 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 FreeXid(xid);
1893 return rc;
1894 }
1895
1896 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1897 if (srvTcp == NULL) {
1898 rc = -ENOMEM;
1899 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001900 kfree(volume_info.UNC);
1901 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001902 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 FreeXid(xid);
1904 return rc;
1905 } else {
1906 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
Steve French50c2f752007-07-13 00:33:32 +00001907 memcpy(&srvTcp->addr.sockAddr, &sin_server,
1908 sizeof (struct sockaddr_in));
1909 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 /* BB Add code for ipv6 case too */
1911 srvTcp->ssocket = csocket;
1912 srvTcp->protocolType = IPV4;
1913 init_waitqueue_head(&srvTcp->response_q);
1914 init_waitqueue_head(&srvTcp->request_q);
1915 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1916 /* at this point we are the only ones with the pointer
1917 to the struct since the kernel thread not created yet
1918 so no need to spinlock this init of tcpStatus */
1919 srvTcp->tcpStatus = CifsNew;
1920 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001921 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001922 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001923 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001924 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001925 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001927 kfree(volume_info.UNC);
1928 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001929 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 FreeXid(xid);
1931 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001932 }
1933 wait_for_completion(&cifsd_complete);
1934 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001935 memcpy(srvTcp->workstation_RFC1001_name,
1936 volume_info.source_rfc1001_name, 16);
1937 memcpy(srvTcp->server_RFC1001_name,
1938 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001939 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 }
1941 }
1942
1943 if (existingCifsSes) {
1944 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001945 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001946 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 /* volume_info.UNC freed at end of function */
1948 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001949 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 pSesInfo = sesInfoAlloc();
1951 if (pSesInfo == NULL)
1952 rc = -ENOMEM;
1953 else {
1954 pSesInfo->server = srvTcp;
1955 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1956 NIPQUAD(sin_server.sin_addr.s_addr));
1957 }
1958
Steve French50c2f752007-07-13 00:33:32 +00001959 if (!rc) {
1960 /* volume_info.password freed at unmount */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (volume_info.password)
1962 pSesInfo->password = volume_info.password;
1963 if (volume_info.username)
1964 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00001965 volume_info.username,
1966 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001967 if (volume_info.domainname) {
1968 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00001969 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00001970 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001971 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001972 strcpy(pSesInfo->domainName,
1973 volume_info.domainname);
1974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001976 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001978 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00001979 rc = cifs_setup_session(xid, pSesInfo,
1980 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001982 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 atomic_inc(&srvTcp->socketUseCount);
1984 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001985 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 }
Steve French50c2f752007-07-13 00:33:32 +00001987
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 /* search for existing tcon to this server share */
1989 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00001990 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00001991 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07001992 volume_info.rsize));
1993 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00001994 } else if ((volume_info.rsize) &&
1995 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001997 else /* default */
1998 cifs_sb->rsize = CIFSMaxBufSize;
1999
Steve French4523cc32007-04-30 20:13:06 +00002000 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002001 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002002 volume_info.wsize));
2003 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002004 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 cifs_sb->wsize = volume_info.wsize;
2006 else
Steve French50c2f752007-07-13 00:33:32 +00002007 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002008 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2009 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002010 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002011 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002012 RFC1001 does not describe what happens when frame
2013 bigger than 128K is sent so use that as max in
2014 conjunction with 52K kvec constraint on arch with 4K
2015 page size */
2016
Steve French4523cc32007-04-30 20:13:06 +00002017 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002018 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002019 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002020 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 }
Steve French2fe87f02006-09-21 07:02:52 +00002022 /* calculate prepath */
2023 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002024 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002025 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2026 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
2027 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002028 } else
Steve French2fe87f02006-09-21 07:02:52 +00002029 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 cifs_sb->mnt_uid = volume_info.linux_uid;
2031 cifs_sb->mnt_gid = volume_info.linux_gid;
2032 cifs_sb->mnt_file_mode = volume_info.file_mode;
2033 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002034 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2035 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
Steve French4523cc32007-04-30 20:13:06 +00002037 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002039 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002041 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002043 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002044 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002045 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002047 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002048 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002049 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002050 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002051 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002052 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002053 if (volume_info.override_uid)
2054 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2055 if (volume_info.override_gid)
2056 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2057 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002058 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2060 }
2061
2062 tcon =
2063 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2064 volume_info.username);
2065 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002066 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 /* we can have only one retry value for a connection
2068 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002069 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 for the retry flag is used */
2071 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002072 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 } else {
2074 tcon = tconInfoAlloc();
2075 if (tcon == NULL)
2076 rc = -ENOMEM;
2077 else {
Steve French50c2f752007-07-13 00:33:32 +00002078 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002079 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
Steve French50c2f752007-07-13 00:33:32 +00002081 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002082 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2084 && (strchr(volume_info.UNC + 3, '/') ==
2085 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002086 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002087 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002088 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002089 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002090 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 FreeXid(xid);
2092 return -ENODEV;
2093 } else {
Steve French8af18972007-02-14 04:42:51 +00002094 /* BB Do we need to wrap sesSem around
2095 * this TCon call and Unix SetFS as
2096 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002097 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 volume_info.UNC,
2099 tcon, cifs_sb->local_nls);
2100 cFYI(1, ("CIFS Tcon rc = %d", rc));
2101 }
2102 if (!rc) {
2103 atomic_inc(&pSesInfo->inUse);
2104 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002105 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 }
2107 }
2108 }
2109 }
Steve French4523cc32007-04-30 20:13:06 +00002110 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2112 sb->s_maxbytes = (u64) 1 << 63;
2113 } else
2114 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2115 }
2116
Steve French8af18972007-02-14 04:42:51 +00002117 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 sb->s_time_gran = 100;
2119
2120/* on error free sesinfo and tcon struct if needed */
2121 if (rc) {
2122 /* if session setup failed, use count is zero but
2123 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002124 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 spin_lock(&GlobalMid_Lock);
2126 srvTcp->tcpStatus = CifsExiting;
2127 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002128 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002129 struct task_struct *tsk;
2130 /* If we could verify that kthread_stop would
2131 always wake up processes blocked in
2132 tcp in recv_mesg then we could remove the
2133 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002134 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002135 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002136 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002137 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002138 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 }
2140 /* If find_unc succeeded then rc == 0 so we can not end */
2141 if (tcon) /* up accidently freeing someone elses tcon struct */
2142 tconInfoFree(tcon);
2143 if (existingCifsSes == NULL) {
2144 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002145 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 (pSesInfo->status == CifsGood)) {
2147 int temp_rc;
2148 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2149 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002150 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002151 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002152 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002153 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002154 force_sig(SIGKILL,
2155 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002156 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002157 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002158 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 } else
2161 cFYI(1, ("No session or bad tcon"));
2162 sesInfoFree(pSesInfo);
2163 /* pSesInfo = NULL; */
2164 }
2165 }
2166 } else {
2167 atomic_inc(&tcon->useCount);
2168 cifs_sb->tcon = tcon;
2169 tcon->ses = pSesInfo;
2170
Steve French82940a42006-03-02 03:24:57 +00002171 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07002172 CIFSSMBQFSDeviceInfo(xid, tcon);
2173 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French50c2f752007-07-13 00:33:32 +00002174
Steve French8af18972007-02-14 04:42:51 +00002175 /* tell server which Unix caps we support */
2176 if (tcon->ses->capabilities & CAP_UNIX)
2177 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002178 else if (cifs_sb->rsize > (1024 * 127)) {
Steve French75865f8c2007-06-24 18:30:48 +00002179 cifs_sb->rsize = 1024 * 127;
2180#ifdef CONFIG_CIFS_DEBUG2
Steve French467a8f82007-06-27 22:41:32 +00002181 cFYI(1, ("no very large read support, rsize 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002182#endif
Steve French50c2f752007-07-13 00:33:32 +00002183
Steve French75865f8c2007-06-24 18:30:48 +00002184 }
Steve French3e844692005-10-03 13:37:24 -07002185 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2186 cifs_sb->wsize = min(cifs_sb->wsize,
2187 (tcon->ses->server->maxBuf -
2188 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002189 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002190 cifs_sb->rsize = min(cifs_sb->rsize,
2191 (tcon->ses->server->maxBuf -
2192 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 }
2194
2195 /* volume_info.password is freed above when existing session found
2196 (in which case it is not needed anymore) but when new sesion is created
2197 the password ptr is put in the new session structure (in which case the
2198 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002199 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002200 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 FreeXid(xid);
2202 return rc;
2203}
2204
2205static int
2206CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002207 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 const struct nls_table *nls_codepage)
2209{
2210 struct smb_hdr *smb_buffer;
2211 struct smb_hdr *smb_buffer_response;
2212 SESSION_SETUP_ANDX *pSMB;
2213 SESSION_SETUP_ANDX *pSMBr;
2214 char *bcc_ptr;
2215 char *user;
2216 char *domain;
2217 int rc = 0;
2218 int remaining_words = 0;
2219 int bytes_returned = 0;
2220 int len;
2221 __u32 capabilities;
2222 __u16 count;
2223
Steve Frencheeac8042006-01-13 21:34:58 -08002224 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002225 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 return -EINVAL;
2227 user = ses->userName;
2228 domain = ses->domainName;
2229 smb_buffer = cifs_buf_get();
2230 if (smb_buffer == NULL) {
2231 return -ENOMEM;
2232 }
2233 smb_buffer_response = smb_buffer;
2234 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2235
2236 /* send SMBsessionSetup here */
2237 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2238 NULL /* no tCon exists yet */ , 13 /* wct */ );
2239
Steve French1982c342005-08-17 12:38:22 -07002240 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 pSMB->req_no_secext.AndXCommand = 0xFF;
2242 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2243 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2244
Steve French50c2f752007-07-13 00:33:32 +00002245 if (ses->server->secMode &
2246 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2248
2249 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2250 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2251 if (ses->capabilities & CAP_UNICODE) {
2252 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2253 capabilities |= CAP_UNICODE;
2254 }
2255 if (ses->capabilities & CAP_STATUS32) {
2256 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2257 capabilities |= CAP_STATUS32;
2258 }
2259 if (ses->capabilities & CAP_DFS) {
2260 smb_buffer->Flags2 |= SMBFLG2_DFS;
2261 capabilities |= CAP_DFS;
2262 }
2263 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2264
Steve French50c2f752007-07-13 00:33:32 +00002265 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002266 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
2268 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002269 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002271 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2272 bcc_ptr += CIFS_SESS_KEY_SIZE;
2273 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2274 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275
2276 if (ses->capabilities & CAP_UNICODE) {
2277 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2278 *bcc_ptr = 0;
2279 bcc_ptr++;
2280 }
Steve French4523cc32007-04-30 20:13:06 +00002281 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002282 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002283 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002285 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 nls_codepage);
2287 /* convert number of 16 bit words to bytes */
2288 bcc_ptr += 2 * bytes_returned;
2289 bcc_ptr += 2; /* trailing null */
2290 if (domain == NULL)
2291 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002292 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 "CIFS_LINUX_DOM", 32, nls_codepage);
2294 else
2295 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002296 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 nls_codepage);
2298 bcc_ptr += 2 * bytes_returned;
2299 bcc_ptr += 2;
2300 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002301 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 32, nls_codepage);
2303 bcc_ptr += 2 * bytes_returned;
2304 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002305 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 32, nls_codepage);
2307 bcc_ptr += 2 * bytes_returned;
2308 bcc_ptr += 2;
2309 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002310 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 64, nls_codepage);
2312 bcc_ptr += 2 * bytes_returned;
2313 bcc_ptr += 2;
2314 } else {
Steve French50c2f752007-07-13 00:33:32 +00002315 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 strncpy(bcc_ptr, user, 200);
2317 bcc_ptr += strnlen(user, 200);
2318 }
2319 *bcc_ptr = 0;
2320 bcc_ptr++;
2321 if (domain == NULL) {
2322 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2323 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2324 } else {
2325 strncpy(bcc_ptr, domain, 64);
2326 bcc_ptr += strnlen(domain, 64);
2327 *bcc_ptr = 0;
2328 bcc_ptr++;
2329 }
2330 strcpy(bcc_ptr, "Linux version ");
2331 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002332 strcpy(bcc_ptr, utsname()->release);
2333 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2335 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2336 }
2337 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2338 smb_buffer->smb_buf_length += count;
2339 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2340
2341 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2342 &bytes_returned, 1);
2343 if (rc) {
2344/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2345 } else if ((smb_buffer_response->WordCount == 3)
2346 || (smb_buffer_response->WordCount == 4)) {
2347 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2348 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2349 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002350 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2351 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2352 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002354 /* response can have either 3 or 4 word count - Samba sends 3 */
2355 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 if ((pSMBr->resp.hdr.WordCount == 3)
2357 || ((pSMBr->resp.hdr.WordCount == 4)
2358 && (blob_len < pSMBr->resp.ByteCount))) {
2359 if (pSMBr->resp.hdr.WordCount == 4)
2360 bcc_ptr += blob_len;
2361
2362 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2363 if ((long) (bcc_ptr) % 2) {
2364 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002365 (BCC(smb_buffer_response) - 1) / 2;
2366 /* Unicode strings must be word
2367 aligned */
2368 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 } else {
2370 remaining_words =
2371 BCC(smb_buffer_response) / 2;
2372 }
2373 len =
2374 UniStrnlen((wchar_t *) bcc_ptr,
2375 remaining_words - 1);
2376/* We look for obvious messed up bcc or strings in response so we do not go off
2377 the end since (at least) WIN2K and Windows XP have a major bug in not null
2378 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002379 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002380 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002381 ses->serverOS = kzalloc(2 * (len + 1),
2382 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002383 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002384 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002386 (__le16 *)bcc_ptr,
2387 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 bcc_ptr += 2 * (len + 1);
2389 remaining_words -= len + 1;
2390 ses->serverOS[2 * len] = 0;
2391 ses->serverOS[1 + (2 * len)] = 0;
2392 if (remaining_words > 0) {
2393 len = UniStrnlen((wchar_t *)bcc_ptr,
2394 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002395 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002396 ses->serverNOS = kzalloc(2 * (len + 1),
2397 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002398 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002399 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002401 (__le16 *)bcc_ptr,
2402 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 bcc_ptr += 2 * (len + 1);
2404 ses->serverNOS[2 * len] = 0;
2405 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002406 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002407 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002408 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 ses->flags |= CIFS_SES_NT4;
2410 }
2411 remaining_words -= len + 1;
2412 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002413 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002414 /* last string is not always null terminated
2415 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002416 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002417 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002419 kzalloc(2*(len+1),
2420 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002421 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002422 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 cifs_strfromUCS_le(ses->serverDomain,
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->serverDomain[2*len] = 0;
2428 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002429 } else { /* else no more room so create
2430 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002431 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002432 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002433 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002434 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002435 }
Steve French50c2f752007-07-13 00:33:32 +00002436 } else { /* no room so create dummy domain
2437 and NOS string */
2438
Steve French433dc242005-04-28 22:41:08 -07002439 /* if these kcallocs fail not much we
2440 can do, but better to not fail the
2441 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002442 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002444 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002445 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002447 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
2449 } else { /* ASCII */
2450 len = strnlen(bcc_ptr, 1024);
2451 if (((long) bcc_ptr + len) - (long)
2452 pByteArea(smb_buffer_response)
2453 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002454 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002455 ses->serverOS = kzalloc(len + 1,
2456 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002457 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002458 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002459 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
2461 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002462 /* null terminate the string */
2463 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 bcc_ptr++;
2465
2466 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002467 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002468 ses->serverNOS = kzalloc(len + 1,
2469 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002470 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002471 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 strncpy(ses->serverNOS, bcc_ptr, len);
2473 bcc_ptr += len;
2474 bcc_ptr[0] = 0;
2475 bcc_ptr++;
2476
2477 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002478 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002479 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002480 ses->serverDomain = kzalloc(len + 1,
2481 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002482 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002483 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002484 strncpy(ses->serverDomain, bcc_ptr,
2485 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 bcc_ptr += len;
2487 bcc_ptr[0] = 0;
2488 bcc_ptr++;
2489 } else
2490 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002491 ("Variable field of length %d "
2492 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 len));
2494 }
2495 } else {
2496 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002497 (" Security Blob Length extends beyond "
2498 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 }
2500 } else {
2501 cERROR(1,
2502 (" Invalid Word count %d: ",
2503 smb_buffer_response->WordCount));
2504 rc = -EIO;
2505 }
Steve French433dc242005-04-28 22:41:08 -07002506sesssetup_nomem: /* do not return an error on nomem for the info strings,
2507 since that could make reconnection harder, and
2508 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 if (smb_buffer)
2510 cifs_buf_release(smb_buffer);
2511
2512 return rc;
2513}
2514
2515static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002517 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 const struct nls_table *nls_codepage)
2519{
2520 struct smb_hdr *smb_buffer;
2521 struct smb_hdr *smb_buffer_response;
2522 SESSION_SETUP_ANDX *pSMB;
2523 SESSION_SETUP_ANDX *pSMBr;
2524 char *bcc_ptr;
2525 char *domain;
2526 int rc = 0;
2527 int remaining_words = 0;
2528 int bytes_returned = 0;
2529 int len;
2530 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2531 PNEGOTIATE_MESSAGE SecurityBlob;
2532 PCHALLENGE_MESSAGE SecurityBlob2;
2533 __u32 negotiate_flags, capabilities;
2534 __u16 count;
2535
Steve French12b3b8f2006-02-09 21:12:47 +00002536 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002537 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 return -EINVAL;
2539 domain = ses->domainName;
2540 *pNTLMv2_flag = FALSE;
2541 smb_buffer = cifs_buf_get();
2542 if (smb_buffer == NULL) {
2543 return -ENOMEM;
2544 }
2545 smb_buffer_response = smb_buffer;
2546 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2547 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2548
2549 /* send SMBsessionSetup here */
2550 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2551 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002552
2553 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2555 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2556
2557 pSMB->req.AndXCommand = 0xFF;
2558 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2559 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2560
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002561 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2563
2564 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2565 CAP_EXTENDED_SECURITY;
2566 if (ses->capabilities & CAP_UNICODE) {
2567 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2568 capabilities |= CAP_UNICODE;
2569 }
2570 if (ses->capabilities & CAP_STATUS32) {
2571 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2572 capabilities |= CAP_STATUS32;
2573 }
2574 if (ses->capabilities & CAP_DFS) {
2575 smb_buffer->Flags2 |= SMBFLG2_DFS;
2576 capabilities |= CAP_DFS;
2577 }
2578 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2579
2580 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2581 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2582 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2583 SecurityBlob->MessageType = NtLmNegotiate;
2584 negotiate_flags =
2585 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002586 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2587 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002589 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002591/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002592 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 /* setup pointers to domain name and workstation name */
2594 bcc_ptr += SecurityBlobLength;
2595
2596 SecurityBlob->WorkstationName.Buffer = 0;
2597 SecurityBlob->WorkstationName.Length = 0;
2598 SecurityBlob->WorkstationName.MaximumLength = 0;
2599
Steve French12b3b8f2006-02-09 21:12:47 +00002600 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2601 along with username on auth request (ie the response to challenge) */
2602 SecurityBlob->DomainName.Buffer = 0;
2603 SecurityBlob->DomainName.Length = 0;
2604 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 if (ses->capabilities & CAP_UNICODE) {
2606 if ((long) bcc_ptr % 2) {
2607 *bcc_ptr = 0;
2608 bcc_ptr++;
2609 }
2610
2611 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002612 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 32, nls_codepage);
2614 bcc_ptr += 2 * bytes_returned;
2615 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002616 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 nls_codepage);
2618 bcc_ptr += 2 * bytes_returned;
2619 bcc_ptr += 2; /* null terminate Linux version */
2620 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002621 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 64, nls_codepage);
2623 bcc_ptr += 2 * bytes_returned;
2624 *(bcc_ptr + 1) = 0;
2625 *(bcc_ptr + 2) = 0;
2626 bcc_ptr += 2; /* null terminate network opsys string */
2627 *(bcc_ptr + 1) = 0;
2628 *(bcc_ptr + 2) = 0;
2629 bcc_ptr += 2; /* null domain */
2630 } else { /* ASCII */
2631 strcpy(bcc_ptr, "Linux version ");
2632 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002633 strcpy(bcc_ptr, utsname()->release);
2634 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2636 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2637 bcc_ptr++; /* empty domain field */
2638 *bcc_ptr = 0;
2639 }
2640 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2641 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2642 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2643 smb_buffer->smb_buf_length += count;
2644 pSMB->req.ByteCount = cpu_to_le16(count);
2645
2646 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2647 &bytes_returned, 1);
2648
2649 if (smb_buffer_response->Status.CifsError ==
2650 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2651 rc = 0;
2652
2653 if (rc) {
2654/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2655 } else if ((smb_buffer_response->WordCount == 3)
2656 || (smb_buffer_response->WordCount == 4)) {
2657 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2658 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2659
2660 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002661 cFYI(1, (" Guest login"));
2662 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
Steve French50c2f752007-07-13 00:33:32 +00002664 bcc_ptr = pByteArea(smb_buffer_response);
2665 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
2667 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2668 if (SecurityBlob2->MessageType != NtLmChallenge) {
2669 cFYI(1,
2670 ("Unexpected NTLMSSP message type received %d",
2671 SecurityBlob2->MessageType));
2672 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002673 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002674 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 if ((pSMBr->resp.hdr.WordCount == 3)
2676 || ((pSMBr->resp.hdr.WordCount == 4)
2677 && (blob_len <
2678 pSMBr->resp.ByteCount))) {
2679
2680 if (pSMBr->resp.hdr.WordCount == 4) {
2681 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002682 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 blob_len));
2684 }
2685
Steve French12b3b8f2006-02-09 21:12:47 +00002686 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687
2688 memcpy(ses->server->cryptKey,
2689 SecurityBlob2->Challenge,
2690 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002691 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002692 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 *pNTLMv2_flag = TRUE;
2694
Steve French50c2f752007-07-13 00:33:32 +00002695 if ((SecurityBlob2->NegotiateFlags &
2696 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002698 ses->server->secMode |=
2699 SECMODE_SIGN_REQUIRED;
2700 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002702 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 SECMODE_SIGN_ENABLED;
2704
2705 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2706 if ((long) (bcc_ptr) % 2) {
2707 remaining_words =
2708 (BCC(smb_buffer_response)
2709 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002710 /* Must word align unicode strings */
2711 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 } else {
2713 remaining_words =
2714 BCC
2715 (smb_buffer_response) / 2;
2716 }
2717 len =
2718 UniStrnlen((wchar_t *) bcc_ptr,
2719 remaining_words - 1);
2720/* We look for obvious messed up bcc or strings in response so we do not go off
2721 the end since (at least) WIN2K and Windows XP have a major bug in not null
2722 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002723 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002724 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002726 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002728 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 bcc_ptr, len,
2730 nls_codepage);
2731 bcc_ptr += 2 * (len + 1);
2732 remaining_words -= len + 1;
2733 ses->serverOS[2 * len] = 0;
2734 ses->serverOS[1 + (2 * len)] = 0;
2735 if (remaining_words > 0) {
2736 len = UniStrnlen((wchar_t *)
2737 bcc_ptr,
2738 remaining_words
2739 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002740 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002742 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 GFP_KERNEL);
2744 cifs_strfromUCS_le(ses->
2745 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002746 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 bcc_ptr,
2748 len,
2749 nls_codepage);
2750 bcc_ptr += 2 * (len + 1);
2751 ses->serverNOS[2 * len] = 0;
2752 ses->serverNOS[1 +
2753 (2 * len)] = 0;
2754 remaining_words -= len + 1;
2755 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002756 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2757 /* last string not always null terminated
2758 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002759 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002761 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 (len +
2763 1),
2764 GFP_KERNEL);
2765 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002766 (ses->serverDomain,
2767 (__le16 *)bcc_ptr,
2768 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 bcc_ptr +=
2770 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002771 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002773 ses->serverDomain
2774 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 = 0;
2776 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002777 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002778 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002780 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002784 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002786 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002787 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002789 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 }
2791 } else { /* ASCII */
2792 len = strnlen(bcc_ptr, 1024);
2793 if (((long) bcc_ptr + len) - (long)
2794 pByteArea(smb_buffer_response)
2795 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002796 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002797 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002799 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 GFP_KERNEL);
2801 strncpy(ses->serverOS,
2802 bcc_ptr, len);
2803
2804 bcc_ptr += len;
2805 bcc_ptr[0] = 0; /* null terminate string */
2806 bcc_ptr++;
2807
2808 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002809 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002811 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 GFP_KERNEL);
2813 strncpy(ses->serverNOS, bcc_ptr, len);
2814 bcc_ptr += len;
2815 bcc_ptr[0] = 0;
2816 bcc_ptr++;
2817
2818 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002819 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002821 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002823 strncpy(ses->serverDomain,
2824 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 bcc_ptr += len;
2826 bcc_ptr[0] = 0;
2827 bcc_ptr++;
2828 } else
2829 cFYI(1,
Steve French12b3b8f2006-02-09 21:12:47 +00002830 ("Variable field of length %d extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 len));
2832 }
2833 } else {
Steve French50c2f752007-07-13 00:33:32 +00002834 cERROR(1, ("Security Blob Length extends beyond"
2835 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 }
2837 } else {
2838 cERROR(1, ("No session structure passed in."));
2839 }
2840 } else {
2841 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002842 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 smb_buffer_response->WordCount));
2844 rc = -EIO;
2845 }
2846
2847 if (smb_buffer)
2848 cifs_buf_release(smb_buffer);
2849
2850 return rc;
2851}
2852static int
2853CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2854 char *ntlm_session_key, int ntlmv2_flag,
2855 const struct nls_table *nls_codepage)
2856{
2857 struct smb_hdr *smb_buffer;
2858 struct smb_hdr *smb_buffer_response;
2859 SESSION_SETUP_ANDX *pSMB;
2860 SESSION_SETUP_ANDX *pSMBr;
2861 char *bcc_ptr;
2862 char *user;
2863 char *domain;
2864 int rc = 0;
2865 int remaining_words = 0;
2866 int bytes_returned = 0;
2867 int len;
2868 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2869 PAUTHENTICATE_MESSAGE SecurityBlob;
2870 __u32 negotiate_flags, capabilities;
2871 __u16 count;
2872
2873 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002874 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 return -EINVAL;
2876 user = ses->userName;
2877 domain = ses->domainName;
2878 smb_buffer = cifs_buf_get();
2879 if (smb_buffer == NULL) {
2880 return -ENOMEM;
2881 }
2882 smb_buffer_response = smb_buffer;
2883 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2884 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2885
2886 /* send SMBsessionSetup here */
2887 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2888 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002889
2890 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2892 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2893 pSMB->req.AndXCommand = 0xFF;
2894 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2895 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2896
2897 pSMB->req.hdr.Uid = ses->Suid;
2898
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002899 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2901
2902 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2903 CAP_EXTENDED_SECURITY;
2904 if (ses->capabilities & CAP_UNICODE) {
2905 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2906 capabilities |= CAP_UNICODE;
2907 }
2908 if (ses->capabilities & CAP_STATUS32) {
2909 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2910 capabilities |= CAP_STATUS32;
2911 }
2912 if (ses->capabilities & CAP_DFS) {
2913 smb_buffer->Flags2 |= SMBFLG2_DFS;
2914 capabilities |= CAP_DFS;
2915 }
2916 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2917
2918 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2919 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2920 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2921 SecurityBlob->MessageType = NtLmAuthenticate;
2922 bcc_ptr += SecurityBlobLength;
Steve French50c2f752007-07-13 00:33:32 +00002923 negotiate_flags =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2925 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2926 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002927 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002929 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2931
2932/* setup pointers to domain name and workstation name */
2933
2934 SecurityBlob->WorkstationName.Buffer = 0;
2935 SecurityBlob->WorkstationName.Length = 0;
2936 SecurityBlob->WorkstationName.MaximumLength = 0;
2937 SecurityBlob->SessionKey.Length = 0;
2938 SecurityBlob->SessionKey.MaximumLength = 0;
2939 SecurityBlob->SessionKey.Buffer = 0;
2940
2941 SecurityBlob->LmChallengeResponse.Length = 0;
2942 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2943 SecurityBlob->LmChallengeResponse.Buffer = 0;
2944
2945 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002946 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002948 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2949 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 SecurityBlob->NtChallengeResponse.Buffer =
2951 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002952 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2953 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954
2955 if (ses->capabilities & CAP_UNICODE) {
2956 if (domain == NULL) {
2957 SecurityBlob->DomainName.Buffer = 0;
2958 SecurityBlob->DomainName.Length = 0;
2959 SecurityBlob->DomainName.MaximumLength = 0;
2960 } else {
2961 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002962 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 nls_codepage);
2964 len *= 2;
2965 SecurityBlob->DomainName.MaximumLength =
2966 cpu_to_le16(len);
2967 SecurityBlob->DomainName.Buffer =
2968 cpu_to_le32(SecurityBlobLength);
2969 bcc_ptr += len;
2970 SecurityBlobLength += len;
2971 SecurityBlob->DomainName.Length =
2972 cpu_to_le16(len);
2973 }
2974 if (user == NULL) {
2975 SecurityBlob->UserName.Buffer = 0;
2976 SecurityBlob->UserName.Length = 0;
2977 SecurityBlob->UserName.MaximumLength = 0;
2978 } else {
2979 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002980 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 nls_codepage);
2982 len *= 2;
2983 SecurityBlob->UserName.MaximumLength =
2984 cpu_to_le16(len);
2985 SecurityBlob->UserName.Buffer =
2986 cpu_to_le32(SecurityBlobLength);
2987 bcc_ptr += len;
2988 SecurityBlobLength += len;
2989 SecurityBlob->UserName.Length =
2990 cpu_to_le16(len);
2991 }
2992
Steve Frenche89dc922005-11-11 15:18:19 -08002993 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 SecurityBlob->WorkstationName.Length *= 2;
2995 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2996 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2997 bcc_ptr += SecurityBlob->WorkstationName.Length;
2998 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2999 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
3000
3001 if ((long) bcc_ptr % 2) {
3002 *bcc_ptr = 0;
3003 bcc_ptr++;
3004 }
3005 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003006 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 32, nls_codepage);
3008 bcc_ptr += 2 * bytes_returned;
3009 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003010 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 nls_codepage);
3012 bcc_ptr += 2 * bytes_returned;
3013 bcc_ptr += 2; /* null term version string */
3014 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003015 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 64, nls_codepage);
3017 bcc_ptr += 2 * bytes_returned;
3018 *(bcc_ptr + 1) = 0;
3019 *(bcc_ptr + 2) = 0;
3020 bcc_ptr += 2; /* null terminate network opsys string */
3021 *(bcc_ptr + 1) = 0;
3022 *(bcc_ptr + 2) = 0;
3023 bcc_ptr += 2; /* null domain */
3024 } else { /* ASCII */
3025 if (domain == NULL) {
3026 SecurityBlob->DomainName.Buffer = 0;
3027 SecurityBlob->DomainName.Length = 0;
3028 SecurityBlob->DomainName.MaximumLength = 0;
3029 } else {
3030 __u16 len;
3031 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3032 strncpy(bcc_ptr, domain, 63);
3033 len = strnlen(domain, 64);
3034 SecurityBlob->DomainName.MaximumLength =
3035 cpu_to_le16(len);
3036 SecurityBlob->DomainName.Buffer =
3037 cpu_to_le32(SecurityBlobLength);
3038 bcc_ptr += len;
3039 SecurityBlobLength += len;
3040 SecurityBlob->DomainName.Length = cpu_to_le16(len);
3041 }
3042 if (user == NULL) {
3043 SecurityBlob->UserName.Buffer = 0;
3044 SecurityBlob->UserName.Length = 0;
3045 SecurityBlob->UserName.MaximumLength = 0;
3046 } else {
3047 __u16 len;
3048 strncpy(bcc_ptr, user, 63);
3049 len = strnlen(user, 64);
3050 SecurityBlob->UserName.MaximumLength =
3051 cpu_to_le16(len);
3052 SecurityBlob->UserName.Buffer =
3053 cpu_to_le32(SecurityBlobLength);
3054 bcc_ptr += len;
3055 SecurityBlobLength += len;
3056 SecurityBlob->UserName.Length = cpu_to_le16(len);
3057 }
3058 /* BB fill in our workstation name if known BB */
3059
3060 strcpy(bcc_ptr, "Linux version ");
3061 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003062 strcpy(bcc_ptr, utsname()->release);
3063 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3065 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3066 bcc_ptr++; /* null domain */
3067 *bcc_ptr = 0;
3068 }
3069 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3070 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3071 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3072 smb_buffer->smb_buf_length += count;
3073 pSMB->req.ByteCount = cpu_to_le16(count);
3074
3075 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3076 &bytes_returned, 1);
3077 if (rc) {
3078/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3079 } else if ((smb_buffer_response->WordCount == 3)
3080 || (smb_buffer_response->WordCount == 4)) {
3081 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3082 __u16 blob_len =
3083 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3084 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003085 cFYI(1, (" Guest login")); /* BB Should we set anything
3086 in SesInfo struct ? */
3087/* if (SecurityBlob2->MessageType != NtLm??) {
3088 cFYI("Unexpected message type on auth response is %d"));
3089 } */
3090
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 if (ses) {
3092 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003093 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003095 /* UID left in wire format */
3096 ses->Suid = smb_buffer_response->Uid;
3097 bcc_ptr = pByteArea(smb_buffer_response);
3098 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 if ((pSMBr->resp.hdr.WordCount == 3)
3100 || ((pSMBr->resp.hdr.WordCount == 4)
3101 && (blob_len <
3102 pSMBr->resp.ByteCount))) {
3103 if (pSMBr->resp.hdr.WordCount == 4) {
3104 bcc_ptr +=
3105 blob_len;
3106 cFYI(1,
3107 ("Security Blob Length %d ",
3108 blob_len));
3109 }
3110
3111 cFYI(1,
3112 ("NTLMSSP response to Authenticate "));
3113
3114 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3115 if ((long) (bcc_ptr) % 2) {
3116 remaining_words =
3117 (BCC(smb_buffer_response)
3118 - 1) / 2;
3119 bcc_ptr++; /* Unicode strings must be word aligned */
3120 } else {
3121 remaining_words = BCC(smb_buffer_response) / 2;
3122 }
3123 len =
3124 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3125/* We look for obvious messed up bcc or strings in response so we do not go off
3126 the end since (at least) WIN2K and Windows XP have a major bug in not null
3127 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003128 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003129 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003131 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003133 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 bcc_ptr, len,
3135 nls_codepage);
3136 bcc_ptr += 2 * (len + 1);
3137 remaining_words -= len + 1;
3138 ses->serverOS[2 * len] = 0;
3139 ses->serverOS[1 + (2 * len)] = 0;
3140 if (remaining_words > 0) {
3141 len = UniStrnlen((wchar_t *)
3142 bcc_ptr,
3143 remaining_words
3144 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003145 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003147 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 GFP_KERNEL);
3149 cifs_strfromUCS_le(ses->
3150 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003151 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 bcc_ptr,
3153 len,
3154 nls_codepage);
3155 bcc_ptr += 2 * (len + 1);
3156 ses->serverNOS[2 * len] = 0;
3157 ses->serverNOS[1+(2*len)] = 0;
3158 remaining_words -= len + 1;
3159 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003160 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003162 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003163 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003165 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 (len +
3167 1),
3168 GFP_KERNEL);
3169 cifs_strfromUCS_le
3170 (ses->
3171 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003172 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 bcc_ptr, len,
3174 nls_codepage);
3175 bcc_ptr +=
3176 2 * (len + 1);
3177 ses->
3178 serverDomain[2
3179 * len]
3180 = 0;
3181 ses->
3182 serverDomain[1
3183 +
3184 (2
3185 *
3186 len)]
3187 = 0;
3188 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003189 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003190 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003191 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003192 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003195 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003196 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003197 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003198 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003199 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 }
3201 } else { /* ASCII */
3202 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003203 if (((long) bcc_ptr + len) -
3204 (long) pByteArea(smb_buffer_response)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003206 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003207 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003208 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 strncpy(ses->serverOS,bcc_ptr, len);
3210
3211 bcc_ptr += len;
3212 bcc_ptr[0] = 0; /* null terminate the string */
3213 bcc_ptr++;
3214
3215 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003216 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003217 ses->serverNOS = kzalloc(len+1,
3218 GFP_KERNEL);
3219 strncpy(ses->serverNOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 bcc_ptr += len;
3221 bcc_ptr[0] = 0;
3222 bcc_ptr++;
3223
3224 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003225 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003226 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003227 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 strncpy(ses->serverDomain, bcc_ptr, len);
3229 bcc_ptr += len;
3230 bcc_ptr[0] = 0;
3231 bcc_ptr++;
3232 } else
3233 cFYI(1,
3234 ("Variable field of length %d extends beyond end of smb ",
3235 len));
3236 }
3237 } else {
3238 cERROR(1,
3239 (" Security Blob Length extends beyond end of SMB"));
3240 }
3241 } else {
3242 cERROR(1, ("No session structure passed in."));
3243 }
3244 } else {
3245 cERROR(1,
3246 (" Invalid Word count %d: ",
3247 smb_buffer_response->WordCount));
3248 rc = -EIO;
3249 }
3250
3251 if (smb_buffer)
3252 cifs_buf_release(smb_buffer);
3253
3254 return rc;
3255}
3256
3257int
3258CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3259 const char *tree, struct cifsTconInfo *tcon,
3260 const struct nls_table *nls_codepage)
3261{
3262 struct smb_hdr *smb_buffer;
3263 struct smb_hdr *smb_buffer_response;
3264 TCONX_REQ *pSMB;
3265 TCONX_RSP *pSMBr;
3266 unsigned char *bcc_ptr;
3267 int rc = 0;
3268 int length;
3269 __u16 count;
3270
3271 if (ses == NULL)
3272 return -EIO;
3273
3274 smb_buffer = cifs_buf_get();
3275 if (smb_buffer == NULL) {
3276 return -ENOMEM;
3277 }
3278 smb_buffer_response = smb_buffer;
3279
3280 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3281 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003282
3283 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 smb_buffer->Uid = ses->Suid;
3285 pSMB = (TCONX_REQ *) smb_buffer;
3286 pSMBr = (TCONX_RSP *) smb_buffer_response;
3287
3288 pSMB->AndXCommand = 0xFF;
3289 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003291 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003292 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003293 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003294 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003295 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003296 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003297 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003298 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3299 specified as required (when that support is added to
3300 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003301 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003302 by Samba (not sure whether other servers allow
3303 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003304#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003305 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003306 (ses->server->secType == LANMAN))
3307 calc_lanman_hash(ses, bcc_ptr);
3308 else
3309#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003310 SMBNTencrypt(ses->password,
3311 ses->server->cryptKey,
3312 bcc_ptr);
3313
Steve French7c7b25b2006-06-01 19:20:10 +00003314 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003315 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003316 /* must align unicode strings */
3317 *bcc_ptr = 0; /* null byte password */
3318 bcc_ptr++;
3319 }
Steve Frencheeac8042006-01-13 21:34:58 -08003320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
Steve French50c2f752007-07-13 00:33:32 +00003322 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003323 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3325
3326 if (ses->capabilities & CAP_STATUS32) {
3327 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3328 }
3329 if (ses->capabilities & CAP_DFS) {
3330 smb_buffer->Flags2 |= SMBFLG2_DFS;
3331 }
3332 if (ses->capabilities & CAP_UNICODE) {
3333 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3334 length =
Steve French50c2f752007-07-13 00:33:32 +00003335 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3336 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003337 (/* server len*/ + 256 /* share len */), nls_codepage);
3338 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 bcc_ptr += 2; /* skip trailing null */
3340 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 strcpy(bcc_ptr, tree);
3342 bcc_ptr += strlen(tree) + 1;
3343 }
3344 strcpy(bcc_ptr, "?????");
3345 bcc_ptr += strlen("?????");
3346 bcc_ptr += 1;
3347 count = bcc_ptr - &pSMB->Password[0];
3348 pSMB->hdr.smb_buf_length += count;
3349 pSMB->ByteCount = cpu_to_le16(count);
3350
3351 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3352
3353 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3354 /* above now done in SendReceive */
3355 if ((rc == 0) && (tcon != NULL)) {
3356 tcon->tidStatus = CifsGood;
3357 tcon->tid = smb_buffer_response->Tid;
3358 bcc_ptr = pByteArea(smb_buffer_response);
3359 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003360 /* skip service field (NB: this field is always ASCII) */
3361 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3363 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3364 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3365 if ((bcc_ptr + (2 * length)) -
3366 pByteArea(smb_buffer_response) <=
3367 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003368 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003370 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003372 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 length, nls_codepage);
3374 bcc_ptr += 2 * length;
3375 bcc_ptr[0] = 0; /* null terminate the string */
3376 bcc_ptr[1] = 0;
3377 bcc_ptr += 2;
3378 }
Steve French50c2f752007-07-13 00:33:32 +00003379 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 } else {
3381 length = strnlen(bcc_ptr, 1024);
3382 if ((bcc_ptr + length) -
3383 pByteArea(smb_buffer_response) <=
3384 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003385 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003387 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 strncpy(tcon->nativeFileSystem, bcc_ptr,
3389 length);
3390 }
Steve French50c2f752007-07-13 00:33:32 +00003391 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003393 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003394 (smb_buffer_response->WordCount == 7))
3395 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003396 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3397 else
3398 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3400 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003401 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 ses->ipc_tid = smb_buffer_response->Tid;
3403 }
3404
3405 if (smb_buffer)
3406 cifs_buf_release(smb_buffer);
3407 return rc;
3408}
3409
3410int
3411cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3412{
3413 int rc = 0;
3414 int xid;
3415 struct cifsSesInfo *ses = NULL;
3416 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003417 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418
3419 xid = GetXid();
3420
3421 if (cifs_sb->tcon) {
3422 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3423 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3424 if (rc == -EBUSY) {
3425 FreeXid(xid);
3426 return 0;
3427 }
3428 tconInfoFree(cifs_sb->tcon);
3429 if ((ses) && (ses->server)) {
3430 /* save off task so we do not refer to ses later */
3431 cifsd_task = ses->server->tsk;
3432 cFYI(1, ("About to do SMBLogoff "));
3433 rc = CIFSSMBLogoff(xid, ses);
3434 if (rc == -EBUSY) {
3435 FreeXid(xid);
3436 return 0;
3437 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003438 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003439 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003440 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003441 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 rc = 0;
3444 } /* else - we have an smb session
3445 left on this socket do not kill cifsd */
3446 } else
3447 cFYI(1, ("No session or bad tcon"));
3448 }
Steve French50c2f752007-07-13 00:33:32 +00003449
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003451 tmp = cifs_sb->prepath;
3452 cifs_sb->prepathlen = 0;
3453 cifs_sb->prepath = NULL;
3454 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003455 if (ses)
3456 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 if (ses)
3458 sesInfoFree(ses);
3459
3460 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003461 return rc; /* BB check if we should always return zero here */
3462}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463
3464int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003465 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466{
3467 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003468 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003470 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
3472 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003473 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003475 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003477 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 rc = -EHOSTDOWN;
3479 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003480 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003482 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 pSesInfo->server->tcpStatus = CifsGood;
3484 else
3485 rc = -EHOSTDOWN;
3486 spin_unlock(&GlobalMid_Lock);
3487
3488 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003489 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 }
3491 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003492 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003494 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003496 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003497 cFYI(1,
3498 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 pSesInfo->server->secMode,
3500 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003501 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003502 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003503 rc = CIFS_SessSetup(xid, pSesInfo,
3504 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003505 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003506 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003507 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003509 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 } else if (extended_security
3511 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3512 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003513 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3515 pSesInfo,
3516 &ntlmv2_flag,
3517 nls_info);
3518 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003519 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003520 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003521 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003522 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 nls_info)) {
3524 rc = -ENOMEM;
3525 goto ss_err_exit;
3526 } else
3527 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003528 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003529 CalcNTLMv2_response(pSesInfo,
3530 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003531 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003532 cifs_calculate_ntlmv2_mac_key(
3533 pSesInfo->server->mac_signing_key,
3534 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 kfree(v2_response);
3536 /* BB Put dummy sig in SessSetup PDU? */
3537 } else {
3538 rc = -ENOMEM;
3539 goto ss_err_exit;
3540 }
3541
3542 } else {
3543 SMBNTencrypt(pSesInfo->password,
3544 pSesInfo->server->cryptKey,
3545 ntlm_session_key);
3546
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003547 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003548 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003549 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003550 ntlm_session_key,
3551 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 }
3553 /* for better security the weaker lanman hash not sent
3554 in AuthSessSetup so we no longer calculate it */
3555
3556 rc = CIFSNTLMSSPAuthSessSetup(xid,
3557 pSesInfo,
3558 ntlm_session_key,
3559 ntlmv2_flag,
3560 nls_info);
3561 }
3562 } else { /* old style NTLM 0.12 session setup */
3563 SMBNTencrypt(pSesInfo->password,
3564 pSesInfo->server->cryptKey,
3565 ntlm_session_key);
3566
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003567 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003568 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003569 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003570 ntlm_session_key, pSesInfo->password);
3571
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 rc = CIFSSessSetup(xid, pSesInfo,
3573 ntlm_session_key, nls_info);
3574 }
3575 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003576 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 } else {
Steve French467a8f82007-06-27 22:41:32 +00003578 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 pSesInfo->status = CifsGood;
3580 }
3581 }
3582ss_err_exit:
3583 return rc;
3584}
3585