blob: cf606910cb68013e1f1fdf8d0fa465aa5b972abf [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
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
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 French2fe87f02006-09-21 07:02:52 +000096 char * prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097};
98
99static int ipv4_connect(struct sockaddr_in *psin_server,
100 struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700101 char * netb_name,
102 char * server_netb_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static int ipv6_connect(struct sockaddr_in6 *psin_server,
104 struct socket **csocket);
105
106
107 /*
108 * cifs tcp session reconnection
109 *
110 * mark tcp session as reconnecting so temporarily locked
111 * mark all smb sessions as reconnecting for tcp session
112 * reconnect tcp session
113 * wake up waiters on reconnection? - (not needed currently)
114 */
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;
123 struct mid_q_entry * mid_entry;
124
125 spin_lock(&GlobalMid_Lock);
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000126 if( kthread_should_stop() ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 /* the demux thread will exit normally
128 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);
153 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
154 tcon->tidStatus = CifsNeedReconnect;
155 }
156 }
157 read_unlock(&GlobalSMBSeslock);
158 /* do not want to be sending data on a socket we are freeing */
159 down(&server->tcpSem);
160 if(server->ssocket) {
161 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
162 server->ssocket->flags));
163 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
164 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
165 server->ssocket->flags));
166 sock_release(server->ssocket);
167 server->ssocket = NULL;
168 }
169
170 spin_lock(&GlobalMid_Lock);
171 list_for_each(tmp, &server->pending_mid_q) {
172 mid_entry = list_entry(tmp, struct
173 mid_q_entry,
174 qhead);
175 if(mid_entry) {
176 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700177 /* Mark other intransit requests as needing
178 retry so we do not immediately mark the
179 session bad again (ie after we reconnect
180 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 mid_entry->midState = MID_RETRY_NEEDED;
182 }
183 }
184 }
185 spin_unlock(&GlobalMid_Lock);
186 up(&server->tcpSem);
187
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000188 while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 {
Steve French6c3d8902006-07-31 22:46:20 +0000190 try_to_freeze();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 if(server->protocolType == IPV6) {
192 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
193 } else {
194 rc = ipv4_connect(&server->addr.sockAddr,
195 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700196 server->workstation_RFC1001_name,
197 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 }
199 if(rc) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700200 cFYI(1,("reconnect error %d",rc));
Steve French0cb766a2005-04-28 22:41:11 -0700201 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 } else {
203 atomic_inc(&tcpSesReconnectCount);
204 spin_lock(&GlobalMid_Lock);
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000205 if( !kthread_should_stop() )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700207 server->sequence_number = 0;
208 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 /* atomic_set(&server->inFlight,0);*/
210 wake_up(&server->response_q);
211 }
212 }
213 return rc;
214}
215
Steve Frenche4eb2952005-04-28 22:41:09 -0700216/*
217 return codes:
218 0 not a transact2, or all data present
219 >0 transact2 with that much data missing
220 -EINVAL = invalid transact2
221
222 */
223static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
224{
225 struct smb_t2_rsp * pSMBt;
226 int total_data_size;
227 int data_in_this_rsp;
228 int remaining;
229
230 if(pSMB->Command != SMB_COM_TRANSACTION2)
231 return 0;
232
233 /* check for plausible wct, bcc and t2 data and parm sizes */
234 /* check for parm and data offset going beyond end of smb */
235 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
236 cFYI(1,("invalid transact2 word count"));
237 return -EINVAL;
238 }
239
240 pSMBt = (struct smb_t2_rsp *)pSMB;
241
242 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
243 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
244
245 remaining = total_data_size - data_in_this_rsp;
246
247 if(remaining == 0)
248 return 0;
249 else if(remaining < 0) {
250 cFYI(1,("total data %d smaller than data in frame %d",
251 total_data_size, data_in_this_rsp));
252 return -EINVAL;
253 } else {
254 cFYI(1,("missing %d bytes from transact2, check next response",
255 remaining));
256 if(total_data_size > maxBufSize) {
257 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
258 total_data_size,maxBufSize));
259 return -EINVAL;
260 }
261 return remaining;
262 }
263}
264
265static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
266{
267 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
268 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
269 int total_data_size;
270 int total_in_buf;
271 int remaining;
272 int total_in_buf2;
273 char * data_area_of_target;
274 char * data_area_of_buf2;
275 __u16 byte_count;
276
277 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
278
279 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
280 cFYI(1,("total data sizes of primary and secondary t2 differ"));
281 }
282
283 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
284
285 remaining = total_data_size - total_in_buf;
286
287 if(remaining < 0)
288 return -EINVAL;
289
290 if(remaining == 0) /* nothing to do, ignore */
291 return 0;
292
293 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
294 if(remaining < total_in_buf2) {
295 cFYI(1,("transact2 2nd response contains too much data"));
296 }
297
298 /* find end of first SMB data area */
299 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
300 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
301 /* validate target area */
302
303 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
304 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
305
306 data_area_of_target += total_in_buf;
307
308 /* copy second buffer into end of first buffer */
309 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
310 total_in_buf += total_in_buf2;
311 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
312 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
313 byte_count += total_in_buf2;
314 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
315
Steve French70ca7342005-09-22 16:32:06 -0700316 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700317 byte_count += total_in_buf2;
318
319 /* BB also add check that we are not beyond maximum buffer size */
320
Steve French70ca7342005-09-22 16:32:06 -0700321 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700322
323 if(remaining == total_in_buf2) {
324 cFYI(1,("found the last secondary response"));
325 return 0; /* we are done */
326 } else /* more responses to go */
327 return 1;
328
329}
330
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331static int
332cifs_demultiplex_thread(struct TCP_Server_Info *server)
333{
334 int length;
335 unsigned int pdu_length, total_read;
336 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700337 struct smb_hdr *bigbuf = NULL;
338 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 struct msghdr smb_msg;
340 struct kvec iov;
341 struct socket *csocket = server->ssocket;
342 struct list_head *tmp;
343 struct cifsSesInfo *ses;
344 struct task_struct *task_to_wake = NULL;
345 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700346 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700347 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700348 int isMultiRsp;
349 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 current->flags |= PF_MEMALLOC;
352 server->tsk = current; /* save process info to wake at shutdown */
353 cFYI(1, ("Demultiplex PID: %d", current->pid));
354 write_lock(&GlobalSMBSeslock);
355 atomic_inc(&tcpSesAllocCount);
356 length = tcpSesAllocCount.counter;
357 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700358 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 if(length > 1) {
360 mempool_resize(cifs_req_poolp,
361 length + cifs_min_rcv,
362 GFP_KERNEL);
363 }
364
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000365 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700366 if (try_to_freeze())
367 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700368 if (bigbuf == NULL) {
369 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000370 if (!bigbuf) {
371 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700372 msleep(3000);
373 /* retry will check if exiting */
374 continue;
375 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000376 } else if (isLargeBuf) {
377 /* we are reusing a dirty large buf, clear its start */
Steve Frenchb8643e12005-04-28 22:41:07 -0700378 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700380
381 if (smallbuf == NULL) {
382 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000383 if (!smallbuf) {
384 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700385 msleep(1000);
386 /* retry will check if exiting */
387 continue;
388 }
389 /* beginning of smb buffer is cleared in our buf_get */
390 } else /* if existing small buf clear beginning */
391 memset(smallbuf, 0, sizeof (struct smb_hdr));
392
393 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700394 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700395 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 iov.iov_base = smb_buffer;
397 iov.iov_len = 4;
398 smb_msg.msg_control = NULL;
399 smb_msg.msg_controllen = 0;
400 length =
401 kernel_recvmsg(csocket, &smb_msg,
402 &iov, 1, 4, 0 /* BB see socket.h flags */);
403
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000404 if ( kthread_should_stop() ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 break;
406 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000407 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000409 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 csocket = server->ssocket;
411 continue;
412 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700413 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 allowing socket to clear and app threads to set
415 tcpStatus CifsNeedReconnect if server hung */
416 continue;
417 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000418 if (server->tcpStatus == CifsNew) {
419 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700420 /* some servers kill the TCP session rather than
421 returning an SMB negprot error, in which
422 case reconnecting here is not going to help,
423 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 break;
425 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000426 if (!try_to_freeze() && (length == -EINTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 cFYI(1,("cifsd thread killed"));
428 break;
429 }
Steve French57337e42005-04-28 22:41:10 -0700430 cFYI(1,("Reconnect after unexpected peek error %d",
431 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 cifs_reconnect(server);
433 csocket = server->ssocket;
434 wake_up(&server->response_q);
435 continue;
Steve French46810cb2005-04-28 22:41:09 -0700436 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700438 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 length));
440 cifs_reconnect(server);
441 csocket = server->ssocket;
442 wake_up(&server->response_q);
443 continue;
444 }
Steve French67010fb2005-04-28 22:41:09 -0700445
Steve French70ca7342005-09-22 16:32:06 -0700446 /* The right amount was read from socket - 4 bytes */
447 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700448
Steve French70ca7342005-09-22 16:32:06 -0700449 /* the first byte big endian of the length field,
450 is actually not part of the length but the type
451 with the most common, zero, as regular data */
452 temp = *((char *) smb_buffer);
453
454 /* Note that FC 1001 length is big endian on the wire,
455 but we convert it here so it is always manipulated
456 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700457 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700458 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700459
Steve French70ca7342005-09-22 16:32:06 -0700460 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
461
462 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700463 continue;
Steve French70ca7342005-09-22 16:32:06 -0700464 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700465 cFYI(1,("Good RFC 1002 session rsp"));
466 continue;
Steve French70ca7342005-09-22 16:32:06 -0700467 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve French46810cb2005-04-28 22:41:09 -0700468 /* we get this from Windows 98 instead of
469 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700470 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700471 pdu_length));
Steve French46810cb2005-04-28 22:41:09 -0700472 if(server->tcpStatus == CifsNew) {
473 /* if nack on negprot (rather than
474 ret of smb negprot error) reconnecting
475 not going to help, ret error to mount */
476 break;
477 } else {
478 /* give server a second to
479 clean up before reconnect attempt */
480 msleep(1000);
481 /* always try 445 first on reconnect
482 since we get NACK on some if we ever
483 connected to port 139 (the NACK is
484 since we do not begin with RFC1001
485 session initialize frame) */
486 server->addr.sockAddr.sin_port =
487 htons(CIFS_PORT);
488 cifs_reconnect(server);
489 csocket = server->ssocket;
490 wake_up(&server->response_q);
491 continue;
492 }
Steve French70ca7342005-09-22 16:32:06 -0700493 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700494 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700495 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
496 length);
Steve French46810cb2005-04-28 22:41:09 -0700497 cifs_reconnect(server);
498 csocket = server->ssocket;
499 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700500 }
501
502 /* else we have an SMB response */
503 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700504 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700506 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700507 cifs_reconnect(server);
508 csocket = server->ssocket;
509 wake_up(&server->response_q);
510 continue;
511 }
512
513 /* else length ok */
514 reconnect = 0;
515
Steve Frenchec637e32005-12-12 20:53:18 -0800516 if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700517 isLargeBuf = TRUE;
518 memcpy(bigbuf, smallbuf, 4);
519 smb_buffer = bigbuf;
520 }
521 length = 0;
522 iov.iov_base = 4 + (char *)smb_buffer;
523 iov.iov_len = pdu_length;
524 for (total_read = 0; total_read < pdu_length;
525 total_read += length) {
526 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
527 pdu_length - total_read, 0);
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000528 if( kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700529 (length == -EINTR)) {
530 /* then will exit */
531 reconnect = 2;
532 break;
533 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700534 cifs_reconnect(server);
535 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700536 /* Reconnect wakes up rspns q */
537 /* Now we will reread sock */
538 reconnect = 1;
539 break;
540 } else if ((length == -ERESTARTSYS) ||
541 (length == -EAGAIN)) {
542 msleep(1); /* minimum sleep to prevent looping,
543 allowing socket to clear and app
544 threads to set tcpStatus
545 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700546 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 } else if (length <= 0) {
548 cERROR(1,("Received no data, expecting %d",
549 pdu_length - total_read));
550 cifs_reconnect(server);
551 csocket = server->ssocket;
552 reconnect = 1;
553 break;
Steve French46810cb2005-04-28 22:41:09 -0700554 }
555 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700556 if(reconnect == 2)
557 break;
558 else if(reconnect == 1)
559 continue;
560
561 length += 4; /* account for rfc1002 hdr */
562
563
564 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000565 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700566 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700567 continue;
568 }
569
570
571 task_to_wake = NULL;
572 spin_lock(&GlobalMid_Lock);
573 list_for_each(tmp, &server->pending_mid_q) {
574 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
575
576 if ((mid_entry->mid == smb_buffer->Mid) &&
577 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
578 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700579 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
580 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700581 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700582 if(mid_entry->resp_buf) {
583 /* merge response - fix up 1st*/
584 if(coalesce_t2(smb_buffer,
585 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000586 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 break;
588 } else {
589 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000590 mid_entry->multiEnd = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 goto multi_t2_fnd;
592 }
593 } else {
594 if(!isLargeBuf) {
595 cERROR(1,("1st trans2 resp needs bigbuf"));
596 /* BB maybe we can fix this up, switch
597 to already allocated large buffer? */
598 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700599 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700600 mid_entry->resp_buf =
601 smb_buffer;
602 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 bigbuf = NULL;
604 }
605 }
606 break;
607 }
608 mid_entry->resp_buf = smb_buffer;
609 if(isLargeBuf)
610 mid_entry->largeBuf = 1;
611 else
612 mid_entry->largeBuf = 0;
613multi_t2_fnd:
614 task_to_wake = mid_entry->tsk;
615 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700616#ifdef CONFIG_CIFS_STATS2
617 mid_entry->when_received = jiffies;
618#endif
Steve French3a5ff612006-07-14 22:37:11 +0000619 /* so we do not time out requests to server
620 which is still responding (since server could
621 be busy but not dead) */
622 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700623 break;
624 }
625 }
626 spin_unlock(&GlobalMid_Lock);
627 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700628 /* Was previous buf put in mpx struct for multi-rsp? */
629 if(!isMultiRsp) {
630 /* smb buffer will be freed by user thread */
631 if(isLargeBuf) {
632 bigbuf = NULL;
633 } else
634 smallbuf = NULL;
635 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700636 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000637 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700638 && (isMultiRsp == FALSE)) {
Steve French39798772006-05-31 22:40:51 +0000639 cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
Steve French70ca7342005-09-22 16:32:06 -0700640 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
641 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000642#ifdef CONFIG_CIFS_DEBUG2
643 cifs_dump_detail(smb_buffer);
644 cifs_dump_mids(server);
645#endif /* CIFS_DEBUG2 */
646
Steve Frenche4eb2952005-04-28 22:41:09 -0700647 }
648 } /* end while !EXITING */
649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 spin_lock(&GlobalMid_Lock);
651 server->tcpStatus = CifsExiting;
652 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700653 /* check if we have blocked requests that need to free */
654 /* Note that cifs_max_pending is normally 50, but
655 can be set at module install time to as little as two */
656 if(atomic_read(&server->inFlight) >= cifs_max_pending)
657 atomic_set(&server->inFlight, cifs_max_pending - 1);
658 /* We do not want to set the max_pending too low or we
659 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 spin_unlock(&GlobalMid_Lock);
661 /* Although there should not be any requests blocked on
662 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700663 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 to the same server - they now will see the session is in exit state
665 and get out of SendReceive. */
666 wake_up_all(&server->request_q);
667 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700668 msleep(125);
669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 if(server->ssocket) {
671 sock_release(csocket);
672 server->ssocket = NULL;
673 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700674 /* buffer usuallly freed in free_mid - need to free it here on exit */
675 if (bigbuf != NULL)
676 cifs_buf_release(bigbuf);
677 if (smallbuf != NULL)
678 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 read_lock(&GlobalSMBSeslock);
681 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700682 /* loop through server session structures attached to this and
683 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 list_for_each(tmp, &GlobalSMBSessionList) {
685 ses =
686 list_entry(tmp, struct cifsSesInfo,
687 cifsSessionList);
688 if (ses->server == server) {
689 ses->status = CifsExiting;
690 ses->server = NULL;
691 }
692 }
693 read_unlock(&GlobalSMBSeslock);
694 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700695 /* although we can not zero the server struct pointer yet,
696 since there are active requests which may depnd on them,
697 mark the corresponding SMB sessions as exiting too */
698 list_for_each(tmp, &GlobalSMBSessionList) {
699 ses = list_entry(tmp, struct cifsSesInfo,
700 cifsSessionList);
701 if (ses->server == server) {
702 ses->status = CifsExiting;
703 }
704 }
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 spin_lock(&GlobalMid_Lock);
707 list_for_each(tmp, &server->pending_mid_q) {
708 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
709 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
710 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700711 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 task_to_wake = mid_entry->tsk;
713 if(task_to_wake) {
714 wake_up_process(task_to_wake);
715 }
716 }
717 }
718 spin_unlock(&GlobalMid_Lock);
719 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700721 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 }
723
Steve Frenchf1914012005-08-18 09:37:34 -0700724 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 /* mpx threads have not exited yet give them
726 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700727 /* due to delays on oplock break requests, we need
728 to wait at least 45 seconds before giving up
729 on a request getting a response and going ahead
730 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700732 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 /* if threads still have not exited they are probably never
734 coming home not much else we can do but free the memory */
735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
737 write_lock(&GlobalSMBSeslock);
738 atomic_dec(&tcpSesAllocCount);
739 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700740
741 /* last chance to mark ses pointers invalid
742 if there are any pointing to this (e.g
743 if a crazy root user tried to kill cifsd
744 kernel thread explicitly this might happen) */
745 list_for_each(tmp, &GlobalSMBSessionList) {
746 ses = list_entry(tmp, struct cifsSesInfo,
747 cifsSessionList);
748 if (ses->server == server) {
749 ses->server = NULL;
750 }
751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700753
754 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if(length > 0) {
756 mempool_resize(cifs_req_poolp,
757 length + cifs_min_rcv,
758 GFP_KERNEL);
759 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return 0;
762}
763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764static int
765cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
766{
767 char *value;
768 char *data;
769 unsigned int temp_len, i, j;
770 char separator[2];
771
772 separator[0] = ',';
773 separator[1] = 0;
774
Linus Torvalds12e36b22006-10-13 08:09:29 -0700775 if (Local_System_Name[0] != 0)
Steve French2cd646a2006-09-28 19:43:08 +0000776 memcpy(vol->source_rfc1001_name, Local_System_Name,15);
777 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700778 char *nodename = utsname()->nodename;
779 int n = strnlen(nodename,15);
Steve French2cd646a2006-09-28 19:43:08 +0000780 memset(vol->source_rfc1001_name,0x20,15);
Linus Torvalds12e36b22006-10-13 08:09:29 -0700781 for(i=0 ; i < n ; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000782 /* does not have to be perfect mapping since field is
783 informational, only used for servers that do not support
784 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700785 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 }
788 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700789 /* null target name indicates to use *SMBSERVR default called name
790 if we end up sending RFC1001 session initialize */
791 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 vol->linux_uid = current->uid; /* current->euid instead? */
793 vol->linux_gid = current->gid;
794 vol->dir_mode = S_IRWXUGO;
795 /* 2767 perms indicate mandatory locking support */
796 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
797
798 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
799 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700800 /* default is always to request posix paths. */
801 vol->posix_paths = 1;
802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (!options)
804 return 1;
805
806 if(strncmp(options,"sep=",4) == 0) {
807 if(options[4] != 0) {
808 separator[0] = options[4];
809 options += 5;
810 } else {
811 cFYI(1,("Null separator not allowed"));
812 }
813 }
814
815 while ((data = strsep(&options, separator)) != NULL) {
816 if (!*data)
817 continue;
818 if ((value = strchr(data, '=')) != NULL)
819 *value++ = '\0';
820
821 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
822 vol->no_xattr = 0;
823 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
824 vol->no_xattr = 1;
825 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000826 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 printk(KERN_WARNING
828 "CIFS: invalid or missing username\n");
829 return 1; /* needs_arg; */
Steve French4b952a92006-10-30 21:46:13 +0000830 } else if(!*value) {
831 /* null user, ie anonymous, authentication */
832 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834 if (strnlen(value, 200) < 200) {
835 vol->username = value;
836 } else {
837 printk(KERN_WARNING "CIFS: username too long\n");
838 return 1;
839 }
840 } else if (strnicmp(data, "pass", 4) == 0) {
841 if (!value) {
842 vol->password = NULL;
843 continue;
844 } else if(value[0] == 0) {
845 /* check if string begins with double comma
846 since that would mean the password really
847 does start with a comma, and would not
848 indicate an empty string */
849 if(value[1] != separator[0]) {
850 vol->password = NULL;
851 continue;
852 }
853 }
854 temp_len = strlen(value);
855 /* removed password length check, NTLM passwords
856 can be arbitrarily long */
857
858 /* if comma in password, the string will be
859 prematurely null terminated. Commas in password are
860 specified across the cifs mount interface by a double
861 comma ie ,, and a comma used as in other cases ie ','
862 as a parameter delimiter/separator is single and due
863 to the strsep above is temporarily zeroed. */
864
865 /* NB: password legally can have multiple commas and
866 the only illegal character in a password is null */
867
Steve French09d1db52005-04-28 22:41:08 -0700868 if ((value[temp_len] == 0) &&
869 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 /* reinsert comma */
871 value[temp_len] = separator[0];
872 temp_len+=2; /* move after the second comma */
873 while(value[temp_len] != 0) {
874 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700875 if (value[temp_len+1] ==
876 separator[0]) {
877 /* skip second comma */
878 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 } else {
880 /* single comma indicating start
881 of next parm */
882 break;
883 }
884 }
885 temp_len++;
886 }
887 if(value[temp_len] == 0) {
888 options = NULL;
889 } else {
890 value[temp_len] = 0;
891 /* point option to start of next parm */
892 options = value + temp_len + 1;
893 }
894 /* go from value to value + temp_len condensing
895 double commas to singles. Note that this ends up
896 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700897 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700898 if(vol->password == NULL) {
899 printk("CIFS: no memory for pass\n");
900 return 1;
901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 for(i=0,j=0;i<temp_len;i++,j++) {
903 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700904 if(value[i] == separator[0]
905 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 /* skip second comma */
907 i++;
908 }
909 }
910 vol->password[j] = 0;
911 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700912 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700913 if(vol->password == NULL) {
914 printk("CIFS: no memory for pass\n");
915 return 1;
916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 strcpy(vol->password, value);
918 }
919 } else if (strnicmp(data, "ip", 2) == 0) {
920 if (!value || !*value) {
921 vol->UNCip = NULL;
922 } else if (strnlen(value, 35) < 35) {
923 vol->UNCip = value;
924 } else {
925 printk(KERN_WARNING "CIFS: ip address too long\n");
926 return 1;
927 }
Steve Frenchbf820672005-12-01 22:32:42 -0800928 } else if (strnicmp(data, "sec", 3) == 0) {
929 if (!value || !*value) {
930 cERROR(1,("no security value specified"));
931 continue;
932 } else if (strnicmp(value, "krb5i", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000933 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000934 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800935 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000936 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
Steve French189acaa2006-06-23 02:33:48 +0000937 CIFSSEC_MAY_KRB5; */
Steve Frenchbf820672005-12-01 22:32:42 -0800938 cERROR(1,("Krb5 cifs privacy not supported"));
939 return 1;
940 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000941 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800942 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000943 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000944 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800945 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000946 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800947 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000948 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000949 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800950 } else if (strnicmp(value, "ntlm", 4) == 0) {
951 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000952 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800953 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000954 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000955 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000956#ifdef CONFIG_CIFS_WEAK_PW_HASH
957 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000958 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000959#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800960 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000961 vol->nullauth = 1;
Steve Frenchbf820672005-12-01 22:32:42 -0800962 } else {
963 cERROR(1,("bad security option: %s", value));
964 return 1;
965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 } else if ((strnicmp(data, "unc", 3) == 0)
967 || (strnicmp(data, "target", 6) == 0)
968 || (strnicmp(data, "path", 4) == 0)) {
969 if (!value || !*value) {
970 printk(KERN_WARNING
971 "CIFS: invalid path to network resource\n");
972 return 1; /* needs_arg; */
973 }
974 if ((temp_len = strnlen(value, 300)) < 300) {
975 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000976 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 return 1;
978 strcpy(vol->UNC,value);
979 if (strncmp(vol->UNC, "//", 2) == 0) {
980 vol->UNC[0] = '\\';
981 vol->UNC[1] = '\\';
982 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
983 printk(KERN_WARNING
984 "CIFS: UNC Path does not begin with // or \\\\ \n");
985 return 1;
986 }
987 } else {
988 printk(KERN_WARNING "CIFS: UNC name too long\n");
989 return 1;
990 }
991 } else if ((strnicmp(data, "domain", 3) == 0)
992 || (strnicmp(data, "workgroup", 5) == 0)) {
993 if (!value || !*value) {
994 printk(KERN_WARNING "CIFS: invalid domain name\n");
995 return 1; /* needs_arg; */
996 }
997 /* BB are there cases in which a comma can be valid in
998 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +0000999 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 vol->domainname = value;
1001 cFYI(1, ("Domain name set"));
1002 } else {
1003 printk(KERN_WARNING "CIFS: domain name too long\n");
1004 return 1;
1005 }
Steve French2fe87f02006-09-21 07:02:52 +00001006 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1007 if (!value || !*value) {
1008 printk(KERN_WARNING
1009 "CIFS: invalid path prefix\n");
1010 return 1; /* needs_arg; */
1011 }
1012 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001013 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001014 temp_len++; /* missing leading slash */
1015 vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001016 if (vol->prepath == NULL)
Steve French2fe87f02006-09-21 07:02:52 +00001017 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001018 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001019 vol->prepath[0] = '/';
1020 strcpy(vol->prepath+1,value);
1021 } else
1022 strcpy(vol->prepath,value);
1023 cFYI(1,("prefix path %s",vol->prepath));
1024 } else {
1025 printk(KERN_WARNING "CIFS: prefix too long\n");
1026 return 1;
1027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 } else if (strnicmp(data, "iocharset", 9) == 0) {
1029 if (!value || !*value) {
1030 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
1031 return 1; /* needs_arg; */
1032 }
1033 if (strnlen(value, 65) < 65) {
Steve French4523cc32007-04-30 20:13:06 +00001034 if (strnicmp(value,"default",7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 vol->iocharset = value;
1036 /* if iocharset not set load_nls_default used by caller */
1037 cFYI(1, ("iocharset set to %s",value));
1038 } else {
1039 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
1040 return 1;
1041 }
1042 } else if (strnicmp(data, "uid", 3) == 0) {
1043 if (value && *value) {
1044 vol->linux_uid =
1045 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001046 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
1048 } else if (strnicmp(data, "gid", 3) == 0) {
1049 if (value && *value) {
1050 vol->linux_gid =
1051 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001052 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054 } else if (strnicmp(data, "file_mode", 4) == 0) {
1055 if (value && *value) {
1056 vol->file_mode =
1057 simple_strtoul(value, &value, 0);
1058 }
1059 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1060 if (value && *value) {
1061 vol->dir_mode =
1062 simple_strtoul(value, &value, 0);
1063 }
1064 } else if (strnicmp(data, "dirmode", 4) == 0) {
1065 if (value && *value) {
1066 vol->dir_mode =
1067 simple_strtoul(value, &value, 0);
1068 }
1069 } else if (strnicmp(data, "port", 4) == 0) {
1070 if (value && *value) {
1071 vol->port =
1072 simple_strtoul(value, &value, 0);
1073 }
1074 } else if (strnicmp(data, "rsize", 5) == 0) {
1075 if (value && *value) {
1076 vol->rsize =
1077 simple_strtoul(value, &value, 0);
1078 }
1079 } else if (strnicmp(data, "wsize", 5) == 0) {
1080 if (value && *value) {
1081 vol->wsize =
1082 simple_strtoul(value, &value, 0);
1083 }
1084 } else if (strnicmp(data, "sockopt", 5) == 0) {
1085 if (value && *value) {
1086 vol->sockopt =
1087 simple_strtoul(value, &value, 0);
1088 }
1089 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1090 if (!value || !*value || (*value == ' ')) {
1091 cFYI(1,("invalid (empty) netbiosname specified"));
1092 } else {
1093 memset(vol->source_rfc1001_name,0x20,15);
1094 for(i=0;i<15;i++) {
1095 /* BB are there cases in which a comma can be
1096 valid in this workstation netbios name (and need
1097 special handling)? */
1098
1099 /* We do not uppercase netbiosname for user */
1100 if (value[i]==0)
1101 break;
1102 else
1103 vol->source_rfc1001_name[i] = value[i];
1104 }
1105 /* The string has 16th byte zero still from
1106 set at top of the function */
Steve French4523cc32007-04-30 20:13:06 +00001107 if ((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001108 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1109 }
1110 } else if (strnicmp(data, "servern", 7) == 0) {
1111 /* servernetbiosname specified override *SMBSERVER */
1112 if (!value || !*value || (*value == ' ')) {
1113 cFYI(1,("empty server netbiosname specified"));
1114 } else {
1115 /* last byte, type, is 0x20 for servr type */
1116 memset(vol->target_rfc1001_name,0x20,16);
1117
1118 for(i=0;i<15;i++) {
1119 /* BB are there cases in which a comma can be
1120 valid in this workstation netbios name (and need
1121 special handling)? */
1122
1123 /* user or mount helper must uppercase netbiosname */
1124 if (value[i]==0)
1125 break;
1126 else
1127 vol->target_rfc1001_name[i] = value[i];
1128 }
1129 /* The string has 16th byte zero still from
1130 set at top of the function */
Steve French4523cc32007-04-30 20:13:06 +00001131 if ((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001132 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 }
1134 } else if (strnicmp(data, "credentials", 4) == 0) {
1135 /* ignore */
1136 } else if (strnicmp(data, "version", 3) == 0) {
1137 /* ignore */
1138 } else if (strnicmp(data, "guest",5) == 0) {
1139 /* ignore */
1140 } else if (strnicmp(data, "rw", 2) == 0) {
1141 vol->rw = TRUE;
1142 } else if ((strnicmp(data, "suid", 4) == 0) ||
1143 (strnicmp(data, "nosuid", 6) == 0) ||
1144 (strnicmp(data, "exec", 4) == 0) ||
1145 (strnicmp(data, "noexec", 6) == 0) ||
1146 (strnicmp(data, "nodev", 5) == 0) ||
1147 (strnicmp(data, "noauto", 6) == 0) ||
1148 (strnicmp(data, "dev", 3) == 0)) {
1149 /* The mount tool or mount.cifs helper (if present)
1150 uses these opts to set flags, and the flags are read
1151 by the kernel vfs layer before we get here (ie
1152 before read super) so there is no point trying to
1153 parse these options again and set anything and it
1154 is ok to just ignore them */
1155 continue;
1156 } else if (strnicmp(data, "ro", 2) == 0) {
1157 vol->rw = FALSE;
1158 } else if (strnicmp(data, "hard", 4) == 0) {
1159 vol->retry = 1;
1160 } else if (strnicmp(data, "soft", 4) == 0) {
1161 vol->retry = 0;
1162 } else if (strnicmp(data, "perm", 4) == 0) {
1163 vol->noperm = 0;
1164 } else if (strnicmp(data, "noperm", 6) == 0) {
1165 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001166 } else if (strnicmp(data, "mapchars", 8) == 0) {
1167 vol->remap = 1;
1168 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1169 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001170 } else if (strnicmp(data, "sfu", 3) == 0) {
1171 vol->sfu_emul = 1;
1172 } else if (strnicmp(data, "nosfu", 5) == 0) {
1173 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001174 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1175 vol->posix_paths = 1;
1176 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1177 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001178 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1179 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001180 vol->nocase = 1;
1181 } else if (strnicmp(data, "brl", 3) == 0) {
1182 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001183 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001184 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001185 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001186 /* turn off mandatory locking in mode
1187 if remote locking is turned off since the
1188 local vfs will do advisory */
1189 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1190 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 } else if (strnicmp(data, "setuids", 7) == 0) {
1192 vol->setuids = 1;
1193 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1194 vol->setuids = 0;
1195 } else if (strnicmp(data, "nohard", 6) == 0) {
1196 vol->retry = 0;
1197 } else if (strnicmp(data, "nosoft", 6) == 0) {
1198 vol->retry = 1;
1199 } else if (strnicmp(data, "nointr", 6) == 0) {
1200 vol->intr = 0;
1201 } else if (strnicmp(data, "intr", 4) == 0) {
1202 vol->intr = 1;
1203 } else if (strnicmp(data, "serverino",7) == 0) {
1204 vol->server_ino = 1;
1205 } else if (strnicmp(data, "noserverino",9) == 0) {
1206 vol->server_ino = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08001207 } else if (strnicmp(data, "cifsacl",7) == 0) {
1208 vol->cifs_acl = 1;
1209 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1210 vol->cifs_acl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 } else if (strnicmp(data, "acl",3) == 0) {
1212 vol->no_psx_acl = 0;
1213 } else if (strnicmp(data, "noacl",5) == 0) {
1214 vol->no_psx_acl = 1;
Steve French750d1152006-06-27 06:28:30 +00001215 } else if (strnicmp(data, "sign",4) == 0) {
1216 vol->secFlg |= CIFSSEC_MUST_SIGN;
1217/* } else if (strnicmp(data, "seal",4) == 0) {
1218 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 } else if (strnicmp(data, "direct",6) == 0) {
1220 vol->direct_io = 1;
1221 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1222 vol->direct_io = 1;
1223 } else if (strnicmp(data, "in6_addr",8) == 0) {
1224 if (!value || !*value) {
1225 vol->in6_addr = NULL;
1226 } else if (strnlen(value, 49) == 48) {
1227 vol->in6_addr = value;
1228 } else {
1229 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1230 return 1;
1231 }
1232 } else if (strnicmp(data, "noac", 4) == 0) {
1233 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1234 } else
1235 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1236 }
1237 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001238 if (devname == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1240 return 1;
1241 }
1242 if ((temp_len = strnlen(devname, 300)) < 300) {
1243 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001244 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 return 1;
1246 strcpy(vol->UNC,devname);
1247 if (strncmp(vol->UNC, "//", 2) == 0) {
1248 vol->UNC[0] = '\\';
1249 vol->UNC[1] = '\\';
1250 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1251 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1252 return 1;
1253 }
1254 } else {
1255 printk(KERN_WARNING "CIFS: UNC name too long\n");
1256 return 1;
1257 }
1258 }
1259 if(vol->UNCip == NULL)
1260 vol->UNCip = &vol->UNC[2];
1261
1262 return 0;
1263}
1264
1265static struct cifsSesInfo *
1266cifs_find_tcp_session(struct in_addr * target_ip_addr,
1267 struct in6_addr *target_ip6_addr,
1268 char *userName, struct TCP_Server_Info **psrvTcp)
1269{
1270 struct list_head *tmp;
1271 struct cifsSesInfo *ses;
1272 *psrvTcp = NULL;
1273 read_lock(&GlobalSMBSeslock);
1274
1275 list_for_each(tmp, &GlobalSMBSessionList) {
1276 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1277 if (ses->server) {
1278 if((target_ip_addr &&
1279 (ses->server->addr.sockAddr.sin_addr.s_addr
1280 == target_ip_addr->s_addr)) || (target_ip6_addr
1281 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1282 target_ip6_addr,sizeof(*target_ip6_addr)))){
1283 /* BB lock server and tcp session and increment use count here?? */
1284 *psrvTcp = ses->server; /* found a match on the TCP session */
1285 /* BB check if reconnection needed */
1286 if (strncmp
1287 (ses->userName, userName,
1288 MAX_USERNAME_SIZE) == 0){
1289 read_unlock(&GlobalSMBSeslock);
1290 return ses; /* found exact match on both tcp and SMB sessions */
1291 }
1292 }
1293 }
1294 /* else tcp and smb sessions need reconnection */
1295 }
1296 read_unlock(&GlobalSMBSeslock);
1297 return NULL;
1298}
1299
1300static struct cifsTconInfo *
1301find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1302{
1303 struct list_head *tmp;
1304 struct cifsTconInfo *tcon;
1305
1306 read_lock(&GlobalSMBSeslock);
1307 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001308 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1310 if (tcon->ses) {
1311 if (tcon->ses->server) {
1312 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001313 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 tcon->ses->server->addr.sockAddr.sin_addr.
1315 s_addr, new_target_ip_addr));
1316 if (tcon->ses->server->addr.sockAddr.sin_addr.
1317 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001318 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 /* found a match on the TCP session */
1320 /* BB check if reconnection needed */
Steve Frenche466e482006-08-15 13:07:18 +00001321 cFYI(1,("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 tcon->treeName, uncName));
1323 if (strncmp
1324 (tcon->treeName, uncName,
1325 MAX_TREE_SIZE) == 0) {
1326 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001327 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 tcon->treeName, uncName));
1329 if (strncmp
1330 (tcon->ses->userName,
1331 userName,
1332 MAX_USERNAME_SIZE) == 0) {
1333 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001334 /* matched smb session
1335 (user name */
1336 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 }
1338 }
1339 }
1340 }
1341 }
1342 }
1343 read_unlock(&GlobalSMBSeslock);
1344 return NULL;
1345}
1346
1347int
1348connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001349 const char *old_path, const struct nls_table *nls_codepage,
1350 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351{
1352 unsigned char *referrals = NULL;
1353 unsigned int num_referrals;
1354 int rc = 0;
1355
1356 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001357 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
1359 /* BB Add in code to: if valid refrl, if not ip address contact
1360 the helper that resolves tcp names, mount to it, try to
1361 tcon to it unmount it if fail */
1362
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001363 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
1365 return rc;
1366}
1367
1368int
1369get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1370 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001371 unsigned int *pnum_referrals,
1372 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
1374 char *temp_unc;
1375 int rc = 0;
1376
1377 *pnum_referrals = 0;
1378
1379 if (pSesInfo->ipc_tid == 0) {
1380 temp_unc = kmalloc(2 /* for slashes */ +
1381 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1382 + 1 + 4 /* slash IPC$ */ + 2,
1383 GFP_KERNEL);
1384 if (temp_unc == NULL)
1385 return -ENOMEM;
1386 temp_unc[0] = '\\';
1387 temp_unc[1] = '\\';
1388 strcpy(temp_unc + 2, pSesInfo->serverName);
1389 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1390 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1391 cFYI(1,
1392 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1393 kfree(temp_unc);
1394 }
1395 if (rc == 0)
1396 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001397 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 return rc;
1400}
1401
1402/* See RFC1001 section 14 on representation of Netbios names */
1403static void rfc1002mangle(char * target,char * source, unsigned int length)
1404{
1405 unsigned int i,j;
1406
1407 for(i=0,j=0;i<(length);i++) {
1408 /* mask a nibble at a time and encode */
1409 target[j] = 'A' + (0x0F & (source[i] >> 4));
1410 target[j+1] = 'A' + (0x0F & source[i]);
1411 j+=2;
1412 }
1413
1414}
1415
1416
1417static int
1418ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001419 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420{
1421 int rc = 0;
1422 int connected = 0;
1423 __be16 orig_port = 0;
1424
1425 if(*csocket == NULL) {
1426 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1427 if (rc < 0) {
1428 cERROR(1, ("Error %d creating socket",rc));
1429 *csocket = NULL;
1430 return rc;
1431 } else {
1432 /* BB other socket options to set KEEPALIVE, NODELAY? */
1433 cFYI(1,("Socket created"));
1434 (*csocket)->sk->sk_allocation = GFP_NOFS;
1435 }
1436 }
1437
1438 psin_server->sin_family = AF_INET;
1439 if(psin_server->sin_port) { /* user overrode default port */
1440 rc = (*csocket)->ops->connect(*csocket,
1441 (struct sockaddr *) psin_server,
1442 sizeof (struct sockaddr_in),0);
1443 if (rc >= 0)
1444 connected = 1;
1445 }
1446
1447 if(!connected) {
1448 /* save original port so we can retry user specified port
1449 later if fall back ports fail this time */
1450 orig_port = psin_server->sin_port;
1451
1452 /* do not retry on the same port we just failed on */
1453 if(psin_server->sin_port != htons(CIFS_PORT)) {
1454 psin_server->sin_port = htons(CIFS_PORT);
1455
1456 rc = (*csocket)->ops->connect(*csocket,
1457 (struct sockaddr *) psin_server,
1458 sizeof (struct sockaddr_in),0);
1459 if (rc >= 0)
1460 connected = 1;
1461 }
1462 }
1463 if (!connected) {
1464 psin_server->sin_port = htons(RFC1001_PORT);
1465 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1466 psin_server, sizeof (struct sockaddr_in),0);
1467 if (rc >= 0)
1468 connected = 1;
1469 }
1470
1471 /* give up here - unless we want to retry on different
1472 protocol families some day */
1473 if (!connected) {
1474 if(orig_port)
1475 psin_server->sin_port = orig_port;
1476 cFYI(1,("Error %d connecting to server via ipv4",rc));
1477 sock_release(*csocket);
1478 *csocket = NULL;
1479 return rc;
1480 }
1481 /* Eventually check for other socket options to change from
1482 the default. sock_setsockopt not used because it expects
1483 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001484 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1485 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001487 /* make the bufsizes depend on wsize/rsize and max requests */
1488 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1489 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1490 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1491 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
1493 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1495 /* some servers require RFC1001 sessinit before sending
1496 negprot - BB check reconnection in case where second
1497 sessinit is sent but no second negprot */
1498 struct rfc1002_session_packet * ses_init_buf;
1499 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001500 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 if(ses_init_buf) {
1502 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001503 if(target_name && (target_name[0] != 0)) {
1504 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1505 target_name, 16);
1506 } else {
1507 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1508 DEFAULT_CIFS_CALLED_NAME,16);
1509 }
1510
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 ses_init_buf->trailer.session_req.calling_len = 32;
1512 /* calling name ends in null (byte 16) from old smb
1513 convention. */
1514 if(netbios_name && (netbios_name[0] !=0)) {
1515 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1516 netbios_name,16);
1517 } else {
1518 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1519 "LINUX_CIFS_CLNT",16);
1520 }
1521 ses_init_buf->trailer.session_req.scope1 = 0;
1522 ses_init_buf->trailer.session_req.scope2 = 0;
1523 smb_buf = (struct smb_hdr *)ses_init_buf;
1524 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1525 smb_buf->smb_buf_length = 0x81000044;
1526 rc = smb_send(*csocket, smb_buf, 0x44,
1527 (struct sockaddr *)psin_server);
1528 kfree(ses_init_buf);
Steve French083d3a22006-03-03 09:53:36 +00001529 msleep(1); /* RFC1001 layer in at least one server
1530 requires very short break before negprot
1531 presumably because not expecting negprot
1532 to follow so fast. This is a simple
1533 solution that works without
1534 complicating the code and causes no
1535 significant slowing down on mount
1536 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 }
1538 /* else the negprot may still work without this
1539 even though malloc failed */
1540
1541 }
1542
1543 return rc;
1544}
1545
1546static int
1547ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1548{
1549 int rc = 0;
1550 int connected = 0;
1551 __be16 orig_port = 0;
1552
1553 if(*csocket == NULL) {
1554 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1555 if (rc < 0) {
1556 cERROR(1, ("Error %d creating ipv6 socket",rc));
1557 *csocket = NULL;
1558 return rc;
1559 } else {
1560 /* BB other socket options to set KEEPALIVE, NODELAY? */
1561 cFYI(1,("ipv6 Socket created"));
1562 (*csocket)->sk->sk_allocation = GFP_NOFS;
1563 }
1564 }
1565
1566 psin_server->sin6_family = AF_INET6;
1567
1568 if(psin_server->sin6_port) { /* user overrode default port */
1569 rc = (*csocket)->ops->connect(*csocket,
1570 (struct sockaddr *) psin_server,
1571 sizeof (struct sockaddr_in6),0);
1572 if (rc >= 0)
1573 connected = 1;
1574 }
1575
1576 if(!connected) {
1577 /* save original port so we can retry user specified port
1578 later if fall back ports fail this time */
1579
1580 orig_port = psin_server->sin6_port;
1581 /* do not retry on the same port we just failed on */
1582 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1583 psin_server->sin6_port = htons(CIFS_PORT);
1584
1585 rc = (*csocket)->ops->connect(*csocket,
1586 (struct sockaddr *) psin_server,
1587 sizeof (struct sockaddr_in6),0);
1588 if (rc >= 0)
1589 connected = 1;
1590 }
1591 }
1592 if (!connected) {
1593 psin_server->sin6_port = htons(RFC1001_PORT);
1594 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1595 psin_server, sizeof (struct sockaddr_in6),0);
1596 if (rc >= 0)
1597 connected = 1;
1598 }
1599
1600 /* give up here - unless we want to retry on different
1601 protocol families some day */
1602 if (!connected) {
1603 if(orig_port)
1604 psin_server->sin6_port = orig_port;
1605 cFYI(1,("Error %d connecting to server via ipv6",rc));
1606 sock_release(*csocket);
1607 *csocket = NULL;
1608 return rc;
1609 }
1610 /* Eventually check for other socket options to change from
1611 the default. sock_setsockopt not used because it expects
1612 user space buffer */
1613 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1614
1615 return rc;
1616}
1617
Steve French8af18972007-02-14 04:42:51 +00001618void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
1619 struct super_block * sb, struct smb_vol * vol_info)
1620{
1621 /* if we are reconnecting then should we check to see if
1622 * any requested capabilities changed locally e.g. via
1623 * remount but we can not do much about it here
1624 * if they have (even if we could detect it by the following)
1625 * Perhaps we could add a backpointer to array of sb from tcon
1626 * or if we change to make all sb to same share the same
1627 * sb as NFS - then we only have one backpointer to sb.
1628 * What if we wanted to mount the server share twice once with
1629 * and once without posixacls or posix paths? */
1630 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
1631
1632
1633 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
1634 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
1635
1636 /* check for reconnect case in which we do not
1637 want to change the mount behavior if we can avoid it */
1638 if(vol_info == NULL) {
1639 /* turn off POSIX ACL and PATHNAMES if not set
1640 originally at mount time */
1641 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1642 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1643 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1644 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
1645
1646
1647
1648
1649 }
1650
1651 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001652 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001653 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001654 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve French8af18972007-02-14 04:42:51 +00001655 cFYI(1,("negotiated posix acl support"));
1656 if(sb)
1657 sb->s_flags |= MS_POSIXACL;
1658 }
1659
Steve French75865f8c2007-06-24 18:30:48 +00001660 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001661 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001662 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve French8af18972007-02-14 04:42:51 +00001663 cFYI(1,("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001664 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001665 CIFS_SB(sb)->mnt_cifs_flags |=
1666 CIFS_MOUNT_POSIX_PATHS;
1667 }
Steve French984acfe2007-04-26 16:42:50 +00001668
1669 /* We might be setting the path sep back to a different
1670 form if we are reconnecting and the server switched its
1671 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001672 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001673 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001674
1675 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1676 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1677 CIFS_SB(sb)->rsize = 127 * 1024;
1678#ifdef CONFIG_CIFS_DEBUG2
1679 cFYI(1,("larger reads not supported by srv"));
1680#endif
1681 }
1682 }
1683
Steve French984acfe2007-04-26 16:42:50 +00001684
Steve French8af18972007-02-14 04:42:51 +00001685 cFYI(1,("Negotiate caps 0x%x",(int)cap));
1686#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001687 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve French8af18972007-02-14 04:42:51 +00001688 cFYI(1,("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001689 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve French8af18972007-02-14 04:42:51 +00001690 cFYI(1,("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001691 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve French8af18972007-02-14 04:42:51 +00001692 cFYI(1,("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001693 if (cap & CIFS_UNIX_XATTR_CAP)
Steve French8af18972007-02-14 04:42:51 +00001694 cFYI(1,("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001695 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve French8af18972007-02-14 04:42:51 +00001696 cFYI(1,("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001697 if (cap & CIFS_UNIX_LARGE_READ_CAP)
1698 cFYI(1,("very large read cap"));
1699 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
1700 cFYI(1,("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001701#endif /* CIFS_DEBUG2 */
1702 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
1703 cFYI(1,("setting capabilities failed"));
1704 }
1705 }
1706}
1707
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708int
1709cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1710 char *mount_data, const char *devname)
1711{
1712 int rc = 0;
1713 int xid;
1714 int address_type = AF_INET;
1715 struct socket *csocket = NULL;
1716 struct sockaddr_in sin_server;
1717 struct sockaddr_in6 sin_server6;
1718 struct smb_vol volume_info;
1719 struct cifsSesInfo *pSesInfo = NULL;
1720 struct cifsSesInfo *existingCifsSes = NULL;
1721 struct cifsTconInfo *tcon = NULL;
1722 struct TCP_Server_Info *srvTcp = NULL;
1723
1724 xid = GetXid();
1725
1726/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1727
1728 memset(&volume_info,0,sizeof(struct smb_vol));
1729 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001730 kfree(volume_info.UNC);
1731 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001732 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 FreeXid(xid);
1734 return -EINVAL;
1735 }
1736
Jeff Layton8426c392007-05-05 03:27:49 +00001737 if (volume_info.nullauth) {
1738 cFYI(1,("null user"));
1739 volume_info.username = NULL;
1740 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 /* BB fixme parse for domain name here */
1742 cFYI(1, ("Username: %s ", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001744 cifserror("No username specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 /* In userspace mount helper we can get user name from alternate
1746 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001747 kfree(volume_info.UNC);
1748 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001749 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 FreeXid(xid);
1751 return -EINVAL;
1752 }
1753
1754 if (volume_info.UNCip && volume_info.UNC) {
1755 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1756
1757 if(rc <= 0) {
1758 /* not ipv4 address, try ipv6 */
1759 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1760 if(rc > 0)
1761 address_type = AF_INET6;
1762 } else {
1763 address_type = AF_INET;
1764 }
1765
1766 if(rc <= 0) {
1767 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001768 kfree(volume_info.UNC);
1769 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001770 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 FreeXid(xid);
1772 return -EINVAL;
1773 }
1774
1775 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1776 /* success */
1777 rc = 0;
1778 } else if (volume_info.UNCip){
1779 /* BB using ip addr as server name connect to the DFS root below */
1780 cERROR(1,("Connecting to DFS root not implemented yet"));
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 } else /* which servers DFS root would we conect to */ {
1787 cERROR(1,
Steve Frenchbf820672005-12-01 22:32:42 -08001788 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001789 kfree(volume_info.UNC);
1790 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001791 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 FreeXid(xid);
1793 return -EINVAL;
1794 }
1795
1796 /* this is needed for ASCII cp to Unicode converts */
1797 if(volume_info.iocharset == NULL) {
1798 cifs_sb->local_nls = load_nls_default();
1799 /* load_nls_default can not return null */
1800 } else {
1801 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1802 if(cifs_sb->local_nls == NULL) {
1803 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
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 -ELIBACC;
1809 }
1810 }
1811
1812 if(address_type == AF_INET)
1813 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1814 NULL /* no ipv6 addr */,
1815 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001816 else if(address_type == AF_INET6) {
1817 cFYI(1,("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1819 &sin_server6.sin6_addr,
1820 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001821 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001822 kfree(volume_info.UNC);
1823 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001824 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 FreeXid(xid);
1826 return -EINVAL;
1827 }
1828
1829
1830 if (srvTcp) {
Steve Frenchbf820672005-12-01 22:32:42 -08001831 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001833 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 sin_server.sin_port = htons(volume_info.port);
1835 else
1836 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001837 if (address_type == AF_INET6) {
1838 cFYI(1,("attempting ipv6 connect"));
1839 /* BB should we allow ipv6 on port 139? */
1840 /* other OS never observed in Wild doing 139 with v6 */
1841 rc = ipv6_connect(&sin_server6,&csocket);
1842 } else
1843 rc = ipv4_connect(&sin_server,&csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001844 volume_info.source_rfc1001_name,
1845 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 if (rc < 0) {
1847 cERROR(1,
Steve French5858ae42007-04-25 11:59:10 +00001848 ("Error connecting to IPv4 socket. Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001849 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001851 kfree(volume_info.UNC);
1852 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001853 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 FreeXid(xid);
1855 return rc;
1856 }
1857
1858 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1859 if (srvTcp == NULL) {
1860 rc = -ENOMEM;
1861 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001862 kfree(volume_info.UNC);
1863 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001864 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 FreeXid(xid);
1866 return rc;
1867 } else {
1868 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1869 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1870 atomic_set(&srvTcp->inFlight,0);
1871 /* BB Add code for ipv6 case too */
1872 srvTcp->ssocket = csocket;
1873 srvTcp->protocolType = IPV4;
1874 init_waitqueue_head(&srvTcp->response_q);
1875 init_waitqueue_head(&srvTcp->request_q);
1876 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1877 /* at this point we are the only ones with the pointer
1878 to the struct since the kernel thread not created yet
1879 so no need to spinlock this init of tcpStatus */
1880 srvTcp->tcpStatus = CifsNew;
1881 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001882 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001883 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001884 rc = PTR_ERR(srvTcp->tsk);
1885 cERROR(1,("error %d create cifsd thread", rc));
1886 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001888 kfree(volume_info.UNC);
1889 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001890 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 FreeXid(xid);
1892 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001893 }
1894 wait_for_completion(&cifsd_complete);
1895 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001897 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001898 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
1900 }
1901
1902 if (existingCifsSes) {
1903 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001904 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001905 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 /* volume_info.UNC freed at end of function */
1907 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001908 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 pSesInfo = sesInfoAlloc();
1910 if (pSesInfo == NULL)
1911 rc = -ENOMEM;
1912 else {
1913 pSesInfo->server = srvTcp;
1914 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1915 NIPQUAD(sin_server.sin_addr.s_addr));
1916 }
1917
1918 if (!rc){
1919 /* volume_info.password freed at unmount */
1920 if (volume_info.password)
1921 pSesInfo->password = volume_info.password;
1922 if (volume_info.username)
1923 strncpy(pSesInfo->userName,
1924 volume_info.username,MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001925 if (volume_info.domainname) {
1926 int len = strlen(volume_info.domainname);
1927 pSesInfo->domainName =
1928 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001929 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001930 strcpy(pSesInfo->domainName,
1931 volume_info.domainname);
1932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001934 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001936 /* BB FIXME need to pass vol->secFlgs BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1938 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001939 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 atomic_inc(&srvTcp->socketUseCount);
1941 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001942 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 }
1944
1945 /* search for existing tcon to this server share */
1946 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00001947 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French0ae0efa2005-10-10 10:57:19 -07001948 cERROR(1,("rsize %d too large, using MaxBufSize",
1949 volume_info.rsize));
1950 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00001951 } else if ((volume_info.rsize) &&
1952 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001954 else /* default */
1955 cifs_sb->rsize = CIFSMaxBufSize;
1956
Steve French4523cc32007-04-30 20:13:06 +00001957 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French75865f8c2007-06-24 18:30:48 +00001958 cERROR(1,("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07001959 volume_info.wsize));
1960 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00001961 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 cifs_sb->wsize = volume_info.wsize;
1963 else
Steve French17cbbaf2006-01-24 20:26:48 -08001964 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08001965 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1966 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08001967 /* old default of CIFSMaxBufSize was too small now
1968 that SMB Write2 can send multiple pages in kvec.
1969 RFC1001 does not describe what happens when frame
1970 bigger than 128K is sent so use that as max in
1971 conjunction with 52K kvec constraint on arch with 4K
1972 page size */
1973
Steve French4523cc32007-04-30 20:13:06 +00001974 if (cifs_sb->rsize < 2048) {
Steve French6cec2ae2006-02-22 17:31:52 -06001975 cifs_sb->rsize = 2048;
1976 /* Windows ME may prefer this */
Steve French75865f8c2007-06-24 18:30:48 +00001977 cFYI(1,("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 }
Steve French2fe87f02006-09-21 07:02:52 +00001979 /* calculate prepath */
1980 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00001981 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00001982 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
1983 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
1984 volume_info.prepath = NULL;
1985 } else
1986 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 cifs_sb->mnt_uid = volume_info.linux_uid;
1988 cifs_sb->mnt_gid = volume_info.linux_gid;
1989 cifs_sb->mnt_file_mode = volume_info.file_mode;
1990 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve Frencheeac8042006-01-13 21:34:58 -08001991 cFYI(1,("file mode: 0x%x dir mode: 0x%x",
1992 cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
Steve French4523cc32007-04-30 20:13:06 +00001994 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00001996 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00001998 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002000 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002001 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002002 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002004 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002005 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002006 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002007 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002008 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002009 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002010 if (volume_info.override_uid)
2011 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2012 if (volume_info.override_gid)
2013 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2014 if (volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002015 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2017 }
2018
2019 tcon =
2020 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2021 volume_info.username);
2022 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002023 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 /* we can have only one retry value for a connection
2025 to a share so for resources mounted more than once
2026 to the same server share the last value passed in
2027 for the retry flag is used */
2028 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002029 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 } else {
2031 tcon = tconInfoAlloc();
2032 if (tcon == NULL)
2033 rc = -ENOMEM;
2034 else {
Steve French8af18972007-02-14 04:42:51 +00002035 /* check for null share name ie connecting to
2036 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037
Steve French8af18972007-02-14 04:42:51 +00002038 /* BB check if this works for exactly length
2039 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2041 && (strchr(volume_info.UNC + 3, '/') ==
2042 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002043 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002044 "", cifs_sb->local_nls,
2045 cifs_sb->mnt_cifs_flags &
2046 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002047 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 FreeXid(xid);
2049 return -ENODEV;
2050 } else {
Steve French8af18972007-02-14 04:42:51 +00002051 /* BB Do we need to wrap sesSem around
2052 * this TCon call and Unix SetFS as
2053 * we do on SessSetup and reconnect? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 rc = CIFSTCon(xid, pSesInfo,
2055 volume_info.UNC,
2056 tcon, cifs_sb->local_nls);
2057 cFYI(1, ("CIFS Tcon rc = %d", rc));
2058 }
2059 if (!rc) {
2060 atomic_inc(&pSesInfo->inUse);
2061 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002062 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 }
2064 }
2065 }
2066 }
Steve French4523cc32007-04-30 20:13:06 +00002067 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2069 sb->s_maxbytes = (u64) 1 << 63;
2070 } else
2071 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2072 }
2073
Steve French8af18972007-02-14 04:42:51 +00002074 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 sb->s_time_gran = 100;
2076
2077/* on error free sesinfo and tcon struct if needed */
2078 if (rc) {
2079 /* if session setup failed, use count is zero but
2080 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002081 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 spin_lock(&GlobalMid_Lock);
2083 srvTcp->tcpStatus = CifsExiting;
2084 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002085 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002086 struct task_struct *tsk;
2087 /* If we could verify that kthread_stop would
2088 always wake up processes blocked in
2089 tcp in recv_mesg then we could remove the
2090 send_sig call */
Jeff5d9c7202007-06-25 22:16:35 +00002091 force_sig(SIGKILL,srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002092 tsk = srvTcp->tsk;
2093 if(tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002094 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 }
2097 /* If find_unc succeeded then rc == 0 so we can not end */
2098 if (tcon) /* up accidently freeing someone elses tcon struct */
2099 tconInfoFree(tcon);
2100 if (existingCifsSes == NULL) {
2101 if (pSesInfo) {
2102 if ((pSesInfo->server) &&
2103 (pSesInfo->status == CifsGood)) {
2104 int temp_rc;
2105 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2106 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002107 if ((temp_rc == -ESHUTDOWN) &&
Jeff5d9c7202007-06-25 22:16:35 +00002108 (pSesInfo->server) &&
2109 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002110 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002111 force_sig(SIGKILL,
2112 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002113 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002114 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002115 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 } else
2118 cFYI(1, ("No session or bad tcon"));
2119 sesInfoFree(pSesInfo);
2120 /* pSesInfo = NULL; */
2121 }
2122 }
2123 } else {
2124 atomic_inc(&tcon->useCount);
2125 cifs_sb->tcon = tcon;
2126 tcon->ses = pSesInfo;
2127
Steve French82940a42006-03-02 03:24:57 +00002128 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07002129 CIFSSMBQFSDeviceInfo(xid, tcon);
2130 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French8af18972007-02-14 04:42:51 +00002131
2132 /* tell server which Unix caps we support */
2133 if (tcon->ses->capabilities & CAP_UNIX)
2134 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve French75865f8c2007-06-24 18:30:48 +00002135 else if(cifs_sb->rsize > (1024 * 127)) {
2136 cifs_sb->rsize = 1024 * 127;
2137#ifdef CONFIG_CIFS_DEBUG2
2138 cFYI(1,("no very large read support, rsize 127K"));
2139#endif
2140
2141 }
Steve French3e844692005-10-03 13:37:24 -07002142 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2143 cifs_sb->wsize = min(cifs_sb->wsize,
2144 (tcon->ses->server->maxBuf -
2145 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002146 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2147 cifs_sb->rsize = min(cifs_sb->rsize,
2148 (tcon->ses->server->maxBuf -
2149 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 }
2151
2152 /* volume_info.password is freed above when existing session found
2153 (in which case it is not needed anymore) but when new sesion is created
2154 the password ptr is put in the new session structure (in which case the
2155 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002156 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002157 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 FreeXid(xid);
2159 return rc;
2160}
2161
2162static int
2163CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002164 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 const struct nls_table *nls_codepage)
2166{
2167 struct smb_hdr *smb_buffer;
2168 struct smb_hdr *smb_buffer_response;
2169 SESSION_SETUP_ANDX *pSMB;
2170 SESSION_SETUP_ANDX *pSMBr;
2171 char *bcc_ptr;
2172 char *user;
2173 char *domain;
2174 int rc = 0;
2175 int remaining_words = 0;
2176 int bytes_returned = 0;
2177 int len;
2178 __u32 capabilities;
2179 __u16 count;
2180
Steve Frencheeac8042006-01-13 21:34:58 -08002181 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002182 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 return -EINVAL;
2184 user = ses->userName;
2185 domain = ses->domainName;
2186 smb_buffer = cifs_buf_get();
2187 if (smb_buffer == NULL) {
2188 return -ENOMEM;
2189 }
2190 smb_buffer_response = smb_buffer;
2191 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2192
2193 /* send SMBsessionSetup here */
2194 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2195 NULL /* no tCon exists yet */ , 13 /* wct */ );
2196
Steve French1982c342005-08-17 12:38:22 -07002197 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 pSMB->req_no_secext.AndXCommand = 0xFF;
2199 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2200 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2201
2202 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2203 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2204
2205 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2206 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2207 if (ses->capabilities & CAP_UNICODE) {
2208 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2209 capabilities |= CAP_UNICODE;
2210 }
2211 if (ses->capabilities & CAP_STATUS32) {
2212 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2213 capabilities |= CAP_STATUS32;
2214 }
2215 if (ses->capabilities & CAP_DFS) {
2216 smb_buffer->Flags2 |= SMBFLG2_DFS;
2217 capabilities |= CAP_DFS;
2218 }
2219 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2220
2221 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002222 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002225 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002227 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2228 bcc_ptr += CIFS_SESS_KEY_SIZE;
2229 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2230 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
2232 if (ses->capabilities & CAP_UNICODE) {
2233 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2234 *bcc_ptr = 0;
2235 bcc_ptr++;
2236 }
Steve French4523cc32007-04-30 20:13:06 +00002237 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002238 bytes_returned = 0; /* skip null user */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 else
2240 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002241 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 nls_codepage);
2243 /* convert number of 16 bit words to bytes */
2244 bcc_ptr += 2 * bytes_returned;
2245 bcc_ptr += 2; /* trailing null */
2246 if (domain == NULL)
2247 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002248 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 "CIFS_LINUX_DOM", 32, nls_codepage);
2250 else
2251 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002252 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 nls_codepage);
2254 bcc_ptr += 2 * bytes_returned;
2255 bcc_ptr += 2;
2256 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002257 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 32, nls_codepage);
2259 bcc_ptr += 2 * bytes_returned;
2260 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002261 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 32, nls_codepage);
2263 bcc_ptr += 2 * bytes_returned;
2264 bcc_ptr += 2;
2265 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002266 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 64, nls_codepage);
2268 bcc_ptr += 2 * bytes_returned;
2269 bcc_ptr += 2;
2270 } else {
Steve French4523cc32007-04-30 20:13:06 +00002271 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 strncpy(bcc_ptr, user, 200);
2273 bcc_ptr += strnlen(user, 200);
2274 }
2275 *bcc_ptr = 0;
2276 bcc_ptr++;
2277 if (domain == NULL) {
2278 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2279 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2280 } else {
2281 strncpy(bcc_ptr, domain, 64);
2282 bcc_ptr += strnlen(domain, 64);
2283 *bcc_ptr = 0;
2284 bcc_ptr++;
2285 }
2286 strcpy(bcc_ptr, "Linux version ");
2287 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002288 strcpy(bcc_ptr, utsname()->release);
2289 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2291 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2292 }
2293 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2294 smb_buffer->smb_buf_length += count;
2295 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2296
2297 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2298 &bytes_returned, 1);
2299 if (rc) {
2300/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2301 } else if ((smb_buffer_response->WordCount == 3)
2302 || (smb_buffer_response->WordCount == 4)) {
2303 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2304 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2305 if (action & GUEST_LOGIN)
2306 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2307 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2308 cFYI(1, ("UID = %d ", ses->Suid));
2309 /* response can have either 3 or 4 word count - Samba sends 3 */
2310 bcc_ptr = pByteArea(smb_buffer_response);
2311 if ((pSMBr->resp.hdr.WordCount == 3)
2312 || ((pSMBr->resp.hdr.WordCount == 4)
2313 && (blob_len < pSMBr->resp.ByteCount))) {
2314 if (pSMBr->resp.hdr.WordCount == 4)
2315 bcc_ptr += blob_len;
2316
2317 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2318 if ((long) (bcc_ptr) % 2) {
2319 remaining_words =
2320 (BCC(smb_buffer_response) - 1) /2;
2321 bcc_ptr++; /* Unicode strings must be word aligned */
2322 } else {
2323 remaining_words =
2324 BCC(smb_buffer_response) / 2;
2325 }
2326 len =
2327 UniStrnlen((wchar_t *) bcc_ptr,
2328 remaining_words - 1);
2329/* We look for obvious messed up bcc or strings in response so we do not go off
2330 the end since (at least) WIN2K and Windows XP have a major bug in not null
2331 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002332 if(ses->serverOS)
2333 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002334 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002335 if(ses->serverOS == NULL)
2336 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002338 (__le16 *)bcc_ptr, len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 bcc_ptr += 2 * (len + 1);
2340 remaining_words -= len + 1;
2341 ses->serverOS[2 * len] = 0;
2342 ses->serverOS[1 + (2 * len)] = 0;
2343 if (remaining_words > 0) {
2344 len = UniStrnlen((wchar_t *)bcc_ptr,
2345 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002346 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002347 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002348 if(ses->serverNOS == NULL)
2349 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002351 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 bcc_ptr += 2 * (len + 1);
2353 ses->serverNOS[2 * len] = 0;
2354 ses->serverNOS[1 + (2 * len)] = 0;
2355 if(strncmp(ses->serverNOS,
2356 "NT LAN Manager 4",16) == 0) {
2357 cFYI(1,("NT4 server"));
2358 ses->flags |= CIFS_SES_NT4;
2359 }
2360 remaining_words -= len + 1;
2361 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002362 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002364 if(ses->serverDomain)
2365 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002367 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002368 if(ses->serverDomain == NULL)
2369 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002371 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 bcc_ptr += 2 * (len + 1);
2373 ses->serverDomain[2*len] = 0;
2374 ses->serverDomain[1+(2*len)] = 0;
2375 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002376 else {
2377 if(ses->serverDomain)
2378 kfree(ses->serverDomain);
Steve French433dc242005-04-28 22:41:08 -07002379 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002380 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002383 /* if these kcallocs fail not much we
2384 can do, but better to not fail the
2385 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002386 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002388 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002389 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002391 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 }
2393 } else { /* ASCII */
2394 len = strnlen(bcc_ptr, 1024);
2395 if (((long) bcc_ptr + len) - (long)
2396 pByteArea(smb_buffer_response)
2397 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002398 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002399 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002400 if(ses->serverOS == NULL)
2401 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 strncpy(ses->serverOS,bcc_ptr, len);
2403
2404 bcc_ptr += len;
2405 bcc_ptr[0] = 0; /* null terminate the string */
2406 bcc_ptr++;
2407
2408 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002409 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002410 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002411 if(ses->serverNOS == NULL)
2412 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 strncpy(ses->serverNOS, bcc_ptr, len);
2414 bcc_ptr += len;
2415 bcc_ptr[0] = 0;
2416 bcc_ptr++;
2417
2418 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002419 if(ses->serverDomain)
2420 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002421 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002422 if(ses->serverDomain == NULL)
2423 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 strncpy(ses->serverDomain, bcc_ptr, len);
2425 bcc_ptr += len;
2426 bcc_ptr[0] = 0;
2427 bcc_ptr++;
2428 } else
2429 cFYI(1,
2430 ("Variable field of length %d extends beyond end of smb ",
2431 len));
2432 }
2433 } else {
2434 cERROR(1,
2435 (" Security Blob Length extends beyond end of SMB"));
2436 }
2437 } else {
2438 cERROR(1,
2439 (" Invalid Word count %d: ",
2440 smb_buffer_response->WordCount));
2441 rc = -EIO;
2442 }
Steve French433dc242005-04-28 22:41:08 -07002443sesssetup_nomem: /* do not return an error on nomem for the info strings,
2444 since that could make reconnection harder, and
2445 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 if (smb_buffer)
2447 cifs_buf_release(smb_buffer);
2448
2449 return rc;
2450}
2451
2452static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2454 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2455 const struct nls_table *nls_codepage)
2456{
2457 struct smb_hdr *smb_buffer;
2458 struct smb_hdr *smb_buffer_response;
2459 SESSION_SETUP_ANDX *pSMB;
2460 SESSION_SETUP_ANDX *pSMBr;
2461 char *bcc_ptr;
2462 char *domain;
2463 int rc = 0;
2464 int remaining_words = 0;
2465 int bytes_returned = 0;
2466 int len;
2467 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2468 PNEGOTIATE_MESSAGE SecurityBlob;
2469 PCHALLENGE_MESSAGE SecurityBlob2;
2470 __u32 negotiate_flags, capabilities;
2471 __u16 count;
2472
Steve French12b3b8f2006-02-09 21:12:47 +00002473 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 if(ses == NULL)
2475 return -EINVAL;
2476 domain = ses->domainName;
2477 *pNTLMv2_flag = FALSE;
2478 smb_buffer = cifs_buf_get();
2479 if (smb_buffer == NULL) {
2480 return -ENOMEM;
2481 }
2482 smb_buffer_response = smb_buffer;
2483 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2484 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2485
2486 /* send SMBsessionSetup here */
2487 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2488 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002489
2490 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2492 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2493
2494 pSMB->req.AndXCommand = 0xFF;
2495 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2496 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2497
2498 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2499 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2500
2501 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2502 CAP_EXTENDED_SECURITY;
2503 if (ses->capabilities & CAP_UNICODE) {
2504 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2505 capabilities |= CAP_UNICODE;
2506 }
2507 if (ses->capabilities & CAP_STATUS32) {
2508 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2509 capabilities |= CAP_STATUS32;
2510 }
2511 if (ses->capabilities & CAP_DFS) {
2512 smb_buffer->Flags2 |= SMBFLG2_DFS;
2513 capabilities |= CAP_DFS;
2514 }
2515 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2516
2517 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2518 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2519 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2520 SecurityBlob->MessageType = NtLmNegotiate;
2521 negotiate_flags =
2522 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002523 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2524 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2526 if(sign_CIFS_PDUs)
2527 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve French39798772006-05-31 22:40:51 +00002528/* if(ntlmv2_support)
2529 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 /* setup pointers to domain name and workstation name */
2531 bcc_ptr += SecurityBlobLength;
2532
2533 SecurityBlob->WorkstationName.Buffer = 0;
2534 SecurityBlob->WorkstationName.Length = 0;
2535 SecurityBlob->WorkstationName.MaximumLength = 0;
2536
Steve French12b3b8f2006-02-09 21:12:47 +00002537 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2538 along with username on auth request (ie the response to challenge) */
2539 SecurityBlob->DomainName.Buffer = 0;
2540 SecurityBlob->DomainName.Length = 0;
2541 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 if (ses->capabilities & CAP_UNICODE) {
2543 if ((long) bcc_ptr % 2) {
2544 *bcc_ptr = 0;
2545 bcc_ptr++;
2546 }
2547
2548 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002549 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 32, nls_codepage);
2551 bcc_ptr += 2 * bytes_returned;
2552 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002553 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 nls_codepage);
2555 bcc_ptr += 2 * bytes_returned;
2556 bcc_ptr += 2; /* null terminate Linux version */
2557 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002558 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 64, nls_codepage);
2560 bcc_ptr += 2 * bytes_returned;
2561 *(bcc_ptr + 1) = 0;
2562 *(bcc_ptr + 2) = 0;
2563 bcc_ptr += 2; /* null terminate network opsys string */
2564 *(bcc_ptr + 1) = 0;
2565 *(bcc_ptr + 2) = 0;
2566 bcc_ptr += 2; /* null domain */
2567 } else { /* ASCII */
2568 strcpy(bcc_ptr, "Linux version ");
2569 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002570 strcpy(bcc_ptr, utsname()->release);
2571 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2573 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2574 bcc_ptr++; /* empty domain field */
2575 *bcc_ptr = 0;
2576 }
2577 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2578 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2579 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2580 smb_buffer->smb_buf_length += count;
2581 pSMB->req.ByteCount = cpu_to_le16(count);
2582
2583 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2584 &bytes_returned, 1);
2585
2586 if (smb_buffer_response->Status.CifsError ==
2587 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2588 rc = 0;
2589
2590 if (rc) {
2591/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2592 } else if ((smb_buffer_response->WordCount == 3)
2593 || (smb_buffer_response->WordCount == 4)) {
2594 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2595 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2596
2597 if (action & GUEST_LOGIN)
2598 cFYI(1, (" Guest login"));
2599 /* Do we want to set anything in SesInfo struct when guest login? */
2600
2601 bcc_ptr = pByteArea(smb_buffer_response);
2602 /* response can have either 3 or 4 word count - Samba sends 3 */
2603
2604 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2605 if (SecurityBlob2->MessageType != NtLmChallenge) {
2606 cFYI(1,
2607 ("Unexpected NTLMSSP message type received %d",
2608 SecurityBlob2->MessageType));
2609 } else if (ses) {
2610 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002611 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 if ((pSMBr->resp.hdr.WordCount == 3)
2613 || ((pSMBr->resp.hdr.WordCount == 4)
2614 && (blob_len <
2615 pSMBr->resp.ByteCount))) {
2616
2617 if (pSMBr->resp.hdr.WordCount == 4) {
2618 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002619 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 blob_len));
2621 }
2622
Steve French12b3b8f2006-02-09 21:12:47 +00002623 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624
2625 memcpy(ses->server->cryptKey,
2626 SecurityBlob2->Challenge,
2627 CIFS_CRYPTO_KEY_SIZE);
Steve French12b3b8f2006-02-09 21:12:47 +00002628 if(SecurityBlob2->NegotiateFlags &
2629 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 *pNTLMv2_flag = TRUE;
2631
2632 if((SecurityBlob2->NegotiateFlags &
2633 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2634 || (sign_CIFS_PDUs > 1))
2635 ses->server->secMode |=
2636 SECMODE_SIGN_REQUIRED;
2637 if ((SecurityBlob2->NegotiateFlags &
2638 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2639 ses->server->secMode |=
2640 SECMODE_SIGN_ENABLED;
2641
2642 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2643 if ((long) (bcc_ptr) % 2) {
2644 remaining_words =
2645 (BCC(smb_buffer_response)
2646 - 1) / 2;
2647 bcc_ptr++; /* Unicode strings must be word aligned */
2648 } else {
2649 remaining_words =
2650 BCC
2651 (smb_buffer_response) / 2;
2652 }
2653 len =
2654 UniStrnlen((wchar_t *) bcc_ptr,
2655 remaining_words - 1);
2656/* We look for obvious messed up bcc or strings in response so we do not go off
2657 the end since (at least) WIN2K and Windows XP have a major bug in not null
2658 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002659 if(ses->serverOS)
2660 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002662 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002664 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 bcc_ptr, len,
2666 nls_codepage);
2667 bcc_ptr += 2 * (len + 1);
2668 remaining_words -= len + 1;
2669 ses->serverOS[2 * len] = 0;
2670 ses->serverOS[1 + (2 * len)] = 0;
2671 if (remaining_words > 0) {
2672 len = UniStrnlen((wchar_t *)
2673 bcc_ptr,
2674 remaining_words
2675 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002676 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002678 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 GFP_KERNEL);
2680 cifs_strfromUCS_le(ses->
2681 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002682 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 bcc_ptr,
2684 len,
2685 nls_codepage);
2686 bcc_ptr += 2 * (len + 1);
2687 ses->serverNOS[2 * len] = 0;
2688 ses->serverNOS[1 +
2689 (2 * len)] = 0;
2690 remaining_words -= len + 1;
2691 if (remaining_words > 0) {
2692 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2693 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002694 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002696 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 (len +
2698 1),
2699 GFP_KERNEL);
2700 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002701 (ses->serverDomain,
2702 (__le16 *)bcc_ptr,
2703 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 bcc_ptr +=
2705 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002706 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002708 ses->serverDomain
2709 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 = 0;
2711 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002712 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002713 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002715 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002719 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002721 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002722 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002724 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 }
2726 } else { /* ASCII */
2727 len = strnlen(bcc_ptr, 1024);
2728 if (((long) bcc_ptr + len) - (long)
2729 pByteArea(smb_buffer_response)
2730 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002731 if(ses->serverOS)
2732 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002734 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 GFP_KERNEL);
2736 strncpy(ses->serverOS,
2737 bcc_ptr, len);
2738
2739 bcc_ptr += len;
2740 bcc_ptr[0] = 0; /* null terminate string */
2741 bcc_ptr++;
2742
2743 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002744 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002746 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 GFP_KERNEL);
2748 strncpy(ses->serverNOS, bcc_ptr, len);
2749 bcc_ptr += len;
2750 bcc_ptr[0] = 0;
2751 bcc_ptr++;
2752
2753 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002754 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002756 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 GFP_KERNEL);
2758 strncpy(ses->serverDomain, bcc_ptr, len);
2759 bcc_ptr += len;
2760 bcc_ptr[0] = 0;
2761 bcc_ptr++;
2762 } else
2763 cFYI(1,
Steve French12b3b8f2006-02-09 21:12:47 +00002764 ("Variable field of length %d extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 len));
2766 }
2767 } else {
2768 cERROR(1,
2769 (" Security Blob Length extends beyond end of SMB"));
2770 }
2771 } else {
2772 cERROR(1, ("No session structure passed in."));
2773 }
2774 } else {
2775 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002776 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 smb_buffer_response->WordCount));
2778 rc = -EIO;
2779 }
2780
2781 if (smb_buffer)
2782 cifs_buf_release(smb_buffer);
2783
2784 return rc;
2785}
2786static int
2787CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2788 char *ntlm_session_key, int ntlmv2_flag,
2789 const struct nls_table *nls_codepage)
2790{
2791 struct smb_hdr *smb_buffer;
2792 struct smb_hdr *smb_buffer_response;
2793 SESSION_SETUP_ANDX *pSMB;
2794 SESSION_SETUP_ANDX *pSMBr;
2795 char *bcc_ptr;
2796 char *user;
2797 char *domain;
2798 int rc = 0;
2799 int remaining_words = 0;
2800 int bytes_returned = 0;
2801 int len;
2802 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2803 PAUTHENTICATE_MESSAGE SecurityBlob;
2804 __u32 negotiate_flags, capabilities;
2805 __u16 count;
2806
2807 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2808 if(ses == NULL)
2809 return -EINVAL;
2810 user = ses->userName;
2811 domain = ses->domainName;
2812 smb_buffer = cifs_buf_get();
2813 if (smb_buffer == NULL) {
2814 return -ENOMEM;
2815 }
2816 smb_buffer_response = smb_buffer;
2817 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2818 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2819
2820 /* send SMBsessionSetup here */
2821 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2822 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002823
2824 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2826 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2827 pSMB->req.AndXCommand = 0xFF;
2828 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2829 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2830
2831 pSMB->req.hdr.Uid = ses->Suid;
2832
2833 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2834 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2835
2836 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2837 CAP_EXTENDED_SECURITY;
2838 if (ses->capabilities & CAP_UNICODE) {
2839 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2840 capabilities |= CAP_UNICODE;
2841 }
2842 if (ses->capabilities & CAP_STATUS32) {
2843 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2844 capabilities |= CAP_STATUS32;
2845 }
2846 if (ses->capabilities & CAP_DFS) {
2847 smb_buffer->Flags2 |= SMBFLG2_DFS;
2848 capabilities |= CAP_DFS;
2849 }
2850 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2851
2852 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2853 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2854 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2855 SecurityBlob->MessageType = NtLmAuthenticate;
2856 bcc_ptr += SecurityBlobLength;
2857 negotiate_flags =
2858 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2859 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2860 0x80000000 | NTLMSSP_NEGOTIATE_128;
2861 if(sign_CIFS_PDUs)
2862 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2863 if(ntlmv2_flag)
2864 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2865
2866/* setup pointers to domain name and workstation name */
2867
2868 SecurityBlob->WorkstationName.Buffer = 0;
2869 SecurityBlob->WorkstationName.Length = 0;
2870 SecurityBlob->WorkstationName.MaximumLength = 0;
2871 SecurityBlob->SessionKey.Length = 0;
2872 SecurityBlob->SessionKey.MaximumLength = 0;
2873 SecurityBlob->SessionKey.Buffer = 0;
2874
2875 SecurityBlob->LmChallengeResponse.Length = 0;
2876 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2877 SecurityBlob->LmChallengeResponse.Buffer = 0;
2878
2879 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002880 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002882 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2883 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 SecurityBlob->NtChallengeResponse.Buffer =
2885 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002886 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2887 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888
2889 if (ses->capabilities & CAP_UNICODE) {
2890 if (domain == NULL) {
2891 SecurityBlob->DomainName.Buffer = 0;
2892 SecurityBlob->DomainName.Length = 0;
2893 SecurityBlob->DomainName.MaximumLength = 0;
2894 } else {
2895 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002896 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 nls_codepage);
2898 len *= 2;
2899 SecurityBlob->DomainName.MaximumLength =
2900 cpu_to_le16(len);
2901 SecurityBlob->DomainName.Buffer =
2902 cpu_to_le32(SecurityBlobLength);
2903 bcc_ptr += len;
2904 SecurityBlobLength += len;
2905 SecurityBlob->DomainName.Length =
2906 cpu_to_le16(len);
2907 }
2908 if (user == NULL) {
2909 SecurityBlob->UserName.Buffer = 0;
2910 SecurityBlob->UserName.Length = 0;
2911 SecurityBlob->UserName.MaximumLength = 0;
2912 } else {
2913 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002914 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 nls_codepage);
2916 len *= 2;
2917 SecurityBlob->UserName.MaximumLength =
2918 cpu_to_le16(len);
2919 SecurityBlob->UserName.Buffer =
2920 cpu_to_le32(SecurityBlobLength);
2921 bcc_ptr += len;
2922 SecurityBlobLength += len;
2923 SecurityBlob->UserName.Length =
2924 cpu_to_le16(len);
2925 }
2926
Steve Frenche89dc922005-11-11 15:18:19 -08002927 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 SecurityBlob->WorkstationName.Length *= 2;
2929 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2930 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2931 bcc_ptr += SecurityBlob->WorkstationName.Length;
2932 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2933 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2934
2935 if ((long) bcc_ptr % 2) {
2936 *bcc_ptr = 0;
2937 bcc_ptr++;
2938 }
2939 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002940 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 32, nls_codepage);
2942 bcc_ptr += 2 * bytes_returned;
2943 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002944 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 nls_codepage);
2946 bcc_ptr += 2 * bytes_returned;
2947 bcc_ptr += 2; /* null term version string */
2948 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002949 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 64, nls_codepage);
2951 bcc_ptr += 2 * bytes_returned;
2952 *(bcc_ptr + 1) = 0;
2953 *(bcc_ptr + 2) = 0;
2954 bcc_ptr += 2; /* null terminate network opsys string */
2955 *(bcc_ptr + 1) = 0;
2956 *(bcc_ptr + 2) = 0;
2957 bcc_ptr += 2; /* null domain */
2958 } else { /* ASCII */
2959 if (domain == NULL) {
2960 SecurityBlob->DomainName.Buffer = 0;
2961 SecurityBlob->DomainName.Length = 0;
2962 SecurityBlob->DomainName.MaximumLength = 0;
2963 } else {
2964 __u16 len;
2965 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2966 strncpy(bcc_ptr, domain, 63);
2967 len = strnlen(domain, 64);
2968 SecurityBlob->DomainName.MaximumLength =
2969 cpu_to_le16(len);
2970 SecurityBlob->DomainName.Buffer =
2971 cpu_to_le32(SecurityBlobLength);
2972 bcc_ptr += len;
2973 SecurityBlobLength += len;
2974 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2975 }
2976 if (user == NULL) {
2977 SecurityBlob->UserName.Buffer = 0;
2978 SecurityBlob->UserName.Length = 0;
2979 SecurityBlob->UserName.MaximumLength = 0;
2980 } else {
2981 __u16 len;
2982 strncpy(bcc_ptr, user, 63);
2983 len = strnlen(user, 64);
2984 SecurityBlob->UserName.MaximumLength =
2985 cpu_to_le16(len);
2986 SecurityBlob->UserName.Buffer =
2987 cpu_to_le32(SecurityBlobLength);
2988 bcc_ptr += len;
2989 SecurityBlobLength += len;
2990 SecurityBlob->UserName.Length = cpu_to_le16(len);
2991 }
2992 /* BB fill in our workstation name if known BB */
2993
2994 strcpy(bcc_ptr, "Linux version ");
2995 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002996 strcpy(bcc_ptr, utsname()->release);
2997 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2999 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3000 bcc_ptr++; /* null domain */
3001 *bcc_ptr = 0;
3002 }
3003 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3004 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3005 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3006 smb_buffer->smb_buf_length += count;
3007 pSMB->req.ByteCount = cpu_to_le16(count);
3008
3009 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3010 &bytes_returned, 1);
3011 if (rc) {
3012/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3013 } else if ((smb_buffer_response->WordCount == 3)
3014 || (smb_buffer_response->WordCount == 4)) {
3015 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3016 __u16 blob_len =
3017 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3018 if (action & GUEST_LOGIN)
3019 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3020/* if(SecurityBlob2->MessageType != NtLm??){
3021 cFYI("Unexpected message type on auth response is %d "));
3022 } */
3023 if (ses) {
3024 cFYI(1,
3025 ("Does UID on challenge %d match auth response UID %d ",
3026 ses->Suid, smb_buffer_response->Uid));
3027 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3028 bcc_ptr = pByteArea(smb_buffer_response);
3029 /* response can have either 3 or 4 word count - Samba sends 3 */
3030 if ((pSMBr->resp.hdr.WordCount == 3)
3031 || ((pSMBr->resp.hdr.WordCount == 4)
3032 && (blob_len <
3033 pSMBr->resp.ByteCount))) {
3034 if (pSMBr->resp.hdr.WordCount == 4) {
3035 bcc_ptr +=
3036 blob_len;
3037 cFYI(1,
3038 ("Security Blob Length %d ",
3039 blob_len));
3040 }
3041
3042 cFYI(1,
3043 ("NTLMSSP response to Authenticate "));
3044
3045 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3046 if ((long) (bcc_ptr) % 2) {
3047 remaining_words =
3048 (BCC(smb_buffer_response)
3049 - 1) / 2;
3050 bcc_ptr++; /* Unicode strings must be word aligned */
3051 } else {
3052 remaining_words = BCC(smb_buffer_response) / 2;
3053 }
3054 len =
3055 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3056/* We look for obvious messed up bcc or strings in response so we do not go off
3057 the end since (at least) WIN2K and Windows XP have a major bug in not null
3058 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00003059 if(ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003060 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003062 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003064 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 bcc_ptr, len,
3066 nls_codepage);
3067 bcc_ptr += 2 * (len + 1);
3068 remaining_words -= len + 1;
3069 ses->serverOS[2 * len] = 0;
3070 ses->serverOS[1 + (2 * len)] = 0;
3071 if (remaining_words > 0) {
3072 len = UniStrnlen((wchar_t *)
3073 bcc_ptr,
3074 remaining_words
3075 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003076 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003078 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 GFP_KERNEL);
3080 cifs_strfromUCS_le(ses->
3081 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003082 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 bcc_ptr,
3084 len,
3085 nls_codepage);
3086 bcc_ptr += 2 * (len + 1);
3087 ses->serverNOS[2 * len] = 0;
3088 ses->serverNOS[1+(2*len)] = 0;
3089 remaining_words -= len + 1;
3090 if (remaining_words > 0) {
3091 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3092 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00003093 if(ses->serverDomain)
3094 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003096 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 (len +
3098 1),
3099 GFP_KERNEL);
3100 cifs_strfromUCS_le
3101 (ses->
3102 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003103 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 bcc_ptr, len,
3105 nls_codepage);
3106 bcc_ptr +=
3107 2 * (len + 1);
3108 ses->
3109 serverDomain[2
3110 * len]
3111 = 0;
3112 ses->
3113 serverDomain[1
3114 +
3115 (2
3116 *
3117 len)]
3118 = 0;
3119 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003120 else {
3121 if(ses->serverDomain)
3122 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003123 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 } else { /* no room so create dummy domain and NOS string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003126 if(ses->serverDomain)
3127 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003128 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003129 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003130 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 }
3132 } else { /* ASCII */
3133 len = strnlen(bcc_ptr, 1024);
3134 if (((long) bcc_ptr + len) -
3135 (long) pByteArea(smb_buffer_response)
3136 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00003137 if(ses->serverOS)
3138 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003139 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 strncpy(ses->serverOS,bcc_ptr, len);
3141
3142 bcc_ptr += len;
3143 bcc_ptr[0] = 0; /* null terminate the string */
3144 bcc_ptr++;
3145
3146 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003147 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003148 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 strncpy(ses->serverNOS, bcc_ptr, len);
3150 bcc_ptr += len;
3151 bcc_ptr[0] = 0;
3152 bcc_ptr++;
3153
3154 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00003155 if(ses->serverDomain)
3156 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003157 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 strncpy(ses->serverDomain, bcc_ptr, len);
3159 bcc_ptr += len;
3160 bcc_ptr[0] = 0;
3161 bcc_ptr++;
3162 } else
3163 cFYI(1,
3164 ("Variable field of length %d extends beyond end of smb ",
3165 len));
3166 }
3167 } else {
3168 cERROR(1,
3169 (" Security Blob Length extends beyond end of SMB"));
3170 }
3171 } else {
3172 cERROR(1, ("No session structure passed in."));
3173 }
3174 } else {
3175 cERROR(1,
3176 (" Invalid Word count %d: ",
3177 smb_buffer_response->WordCount));
3178 rc = -EIO;
3179 }
3180
3181 if (smb_buffer)
3182 cifs_buf_release(smb_buffer);
3183
3184 return rc;
3185}
3186
3187int
3188CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3189 const char *tree, struct cifsTconInfo *tcon,
3190 const struct nls_table *nls_codepage)
3191{
3192 struct smb_hdr *smb_buffer;
3193 struct smb_hdr *smb_buffer_response;
3194 TCONX_REQ *pSMB;
3195 TCONX_RSP *pSMBr;
3196 unsigned char *bcc_ptr;
3197 int rc = 0;
3198 int length;
3199 __u16 count;
3200
3201 if (ses == NULL)
3202 return -EIO;
3203
3204 smb_buffer = cifs_buf_get();
3205 if (smb_buffer == NULL) {
3206 return -ENOMEM;
3207 }
3208 smb_buffer_response = smb_buffer;
3209
3210 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3211 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003212
3213 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 smb_buffer->Uid = ses->Suid;
3215 pSMB = (TCONX_REQ *) smb_buffer;
3216 pSMBr = (TCONX_RSP *) smb_buffer_response;
3217
3218 pSMB->AndXCommand = 0xFF;
3219 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 bcc_ptr = &pSMB->Password[0];
Steve Frencheeac8042006-01-13 21:34:58 -08003221 if((ses->server->secMode) & SECMODE_USER) {
3222 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003223 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003224 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003225 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003226 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003227 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003228 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3229 specified as required (when that support is added to
3230 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003231 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003232 by Samba (not sure whether other servers allow
3233 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003234#ifdef CONFIG_CIFS_WEAK_PW_HASH
3235 if((extended_security & CIFSSEC_MAY_LANMAN) &&
3236 (ses->server->secType == LANMAN))
3237 calc_lanman_hash(ses, bcc_ptr);
3238 else
3239#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003240 SMBNTencrypt(ses->password,
3241 ses->server->cryptKey,
3242 bcc_ptr);
3243
Steve French7c7b25b2006-06-01 19:20:10 +00003244 bcc_ptr += CIFS_SESS_KEY_SIZE;
3245 if(ses->capabilities & CAP_UNICODE) {
3246 /* must align unicode strings */
3247 *bcc_ptr = 0; /* null byte password */
3248 bcc_ptr++;
3249 }
Steve Frencheeac8042006-01-13 21:34:58 -08003250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251
Steve Frencha878fb22006-05-30 18:04:19 +00003252 if(ses->server->secMode &
3253 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3255
3256 if (ses->capabilities & CAP_STATUS32) {
3257 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3258 }
3259 if (ses->capabilities & CAP_DFS) {
3260 smb_buffer->Flags2 |= SMBFLG2_DFS;
3261 }
3262 if (ses->capabilities & CAP_UNICODE) {
3263 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3264 length =
Steve Frencha878fb22006-05-30 18:04:19 +00003265 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3266 6 /* max utf8 char length in bytes */ *
3267 (/* server len*/ + 256 /* share len */), nls_codepage);
3268 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 bcc_ptr += 2; /* skip trailing null */
3270 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 strcpy(bcc_ptr, tree);
3272 bcc_ptr += strlen(tree) + 1;
3273 }
3274 strcpy(bcc_ptr, "?????");
3275 bcc_ptr += strlen("?????");
3276 bcc_ptr += 1;
3277 count = bcc_ptr - &pSMB->Password[0];
3278 pSMB->hdr.smb_buf_length += count;
3279 pSMB->ByteCount = cpu_to_le16(count);
3280
3281 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3282
3283 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3284 /* above now done in SendReceive */
3285 if ((rc == 0) && (tcon != NULL)) {
3286 tcon->tidStatus = CifsGood;
3287 tcon->tid = smb_buffer_response->Tid;
3288 bcc_ptr = pByteArea(smb_buffer_response);
3289 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3290 /* skip service field (NB: this field is always ASCII) */
3291 bcc_ptr += length + 1;
3292 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3293 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3294 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3295 if ((bcc_ptr + (2 * length)) -
3296 pByteArea(smb_buffer_response) <=
3297 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003298 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003300 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003302 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 length, nls_codepage);
3304 bcc_ptr += 2 * length;
3305 bcc_ptr[0] = 0; /* null terminate the string */
3306 bcc_ptr[1] = 0;
3307 bcc_ptr += 2;
3308 }
3309 /* else do not bother copying these informational fields */
3310 } else {
3311 length = strnlen(bcc_ptr, 1024);
3312 if ((bcc_ptr + length) -
3313 pByteArea(smb_buffer_response) <=
3314 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003315 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003317 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 strncpy(tcon->nativeFileSystem, bcc_ptr,
3319 length);
3320 }
3321 /* else do not bother copying these informational fields */
3322 }
Steve French1a4e15a2006-10-12 21:33:51 +00003323 if((smb_buffer_response->WordCount == 3) ||
3324 (smb_buffer_response->WordCount == 7))
3325 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003326 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3327 else
3328 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3330 } else if ((rc == 0) && tcon == NULL) {
3331 /* all we need to save for IPC$ connection */
3332 ses->ipc_tid = smb_buffer_response->Tid;
3333 }
3334
3335 if (smb_buffer)
3336 cifs_buf_release(smb_buffer);
3337 return rc;
3338}
3339
3340int
3341cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3342{
3343 int rc = 0;
3344 int xid;
3345 struct cifsSesInfo *ses = NULL;
3346 struct task_struct *cifsd_task;
Steve French2fe87f02006-09-21 07:02:52 +00003347 char * tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348
3349 xid = GetXid();
3350
3351 if (cifs_sb->tcon) {
3352 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3353 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3354 if (rc == -EBUSY) {
3355 FreeXid(xid);
3356 return 0;
3357 }
3358 tconInfoFree(cifs_sb->tcon);
3359 if ((ses) && (ses->server)) {
3360 /* save off task so we do not refer to ses later */
3361 cifsd_task = ses->server->tsk;
3362 cFYI(1, ("About to do SMBLogoff "));
3363 rc = CIFSSMBLogoff(xid, ses);
3364 if (rc == -EBUSY) {
3365 FreeXid(xid);
3366 return 0;
3367 } else if (rc == -ESHUTDOWN) {
Jeff5d9c7202007-06-25 22:16:35 +00003368 cFYI(1,("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003369 if (cifsd_task) {
Jeff5d9c7202007-06-25 22:16:35 +00003370 force_sig(SIGKILL,cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003371 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 rc = 0;
3374 } /* else - we have an smb session
3375 left on this socket do not kill cifsd */
3376 } else
3377 cFYI(1, ("No session or bad tcon"));
3378 }
3379
3380 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003381 tmp = cifs_sb->prepath;
3382 cifs_sb->prepathlen = 0;
3383 cifs_sb->prepath = NULL;
3384 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003385 if (ses)
3386 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 if (ses)
3388 sesInfoFree(ses);
3389
3390 FreeXid(xid);
3391 return rc; /* BB check if we should always return zero here */
3392}
3393
3394int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3395 struct nls_table * nls_info)
3396{
3397 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003398 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003400 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401
3402 /* what if server changes its buffer size after dropping the session? */
3403 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3404 rc = CIFSSMBNegotiate(xid, pSesInfo);
3405 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3406 rc = CIFSSMBNegotiate(xid, pSesInfo);
3407 if(rc == -EAGAIN)
3408 rc = -EHOSTDOWN;
3409 }
3410 if(rc == 0) {
3411 spin_lock(&GlobalMid_Lock);
3412 if(pSesInfo->server->tcpStatus != CifsExiting)
3413 pSesInfo->server->tcpStatus = CifsGood;
3414 else
3415 rc = -EHOSTDOWN;
3416 spin_unlock(&GlobalMid_Lock);
3417
3418 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003419 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 }
3421 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003422 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 pSesInfo->capabilities = pSesInfo->server->capabilities;
3424 if(linuxExtEnabled == 0)
3425 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003426 /* pSesInfo->sequence_number = 0;*/
Steve French175ec9e2006-09-30 01:07:38 +00003427 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 pSesInfo->server->secMode,
3429 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003430 pSesInfo->server->timeAdj));
Steve French189acaa2006-06-23 02:33:48 +00003431 if(experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003432 rc = CIFS_SessSetup(xid, pSesInfo,
3433 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003434 else if (extended_security
Steve French175ec9e2006-09-30 01:07:38 +00003435 && (pSesInfo->capabilities
3436 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003438 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 } else if (extended_security
3440 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3441 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003442 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3444 pSesInfo,
3445 &ntlmv2_flag,
3446 nls_info);
3447 if (!rc) {
3448 if(ntlmv2_flag) {
3449 char * v2_response;
Steve French175ec9e2006-09-30 01:07:38 +00003450 cFYI(1,("more secure NTLM ver2 hash"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3452 nls_info)) {
3453 rc = -ENOMEM;
3454 goto ss_err_exit;
3455 } else
3456 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3457 if(v2_response) {
3458 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003459 /* if(first_time)
3460 cifs_calculate_ntlmv2_mac_key(
3461 pSesInfo->server->mac_signing_key,
3462 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 kfree(v2_response);
3464 /* BB Put dummy sig in SessSetup PDU? */
3465 } else {
3466 rc = -ENOMEM;
3467 goto ss_err_exit;
3468 }
3469
3470 } else {
3471 SMBNTencrypt(pSesInfo->password,
3472 pSesInfo->server->cryptKey,
3473 ntlm_session_key);
3474
Steve Frenchad009ac2005-04-28 22:41:05 -07003475 if(first_time)
3476 cifs_calculate_mac_key(
3477 pSesInfo->server->mac_signing_key,
3478 ntlm_session_key,
3479 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 }
3481 /* for better security the weaker lanman hash not sent
3482 in AuthSessSetup so we no longer calculate it */
3483
3484 rc = CIFSNTLMSSPAuthSessSetup(xid,
3485 pSesInfo,
3486 ntlm_session_key,
3487 ntlmv2_flag,
3488 nls_info);
3489 }
3490 } else { /* old style NTLM 0.12 session setup */
3491 SMBNTencrypt(pSesInfo->password,
3492 pSesInfo->server->cryptKey,
3493 ntlm_session_key);
3494
Steve Frenchad009ac2005-04-28 22:41:05 -07003495 if(first_time)
3496 cifs_calculate_mac_key(
3497 pSesInfo->server->mac_signing_key,
3498 ntlm_session_key, pSesInfo->password);
3499
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 rc = CIFSSessSetup(xid, pSesInfo,
3501 ntlm_session_key, nls_info);
3502 }
3503 if (rc) {
3504 cERROR(1,("Send error in SessSetup = %d",rc));
3505 } else {
3506 cFYI(1,("CIFS Session Established successfully"));
3507 pSesInfo->status = CifsGood;
3508 }
3509 }
3510ss_err_exit:
3511 return rc;
3512}
3513