blob: 0a1b8bd1dfcbcf113274107b6ea3bb491bd03cd3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French5815449d2006-02-14 01:36:20 +00004 * Copyright (C) International Business Machines Corp., 2002,2006
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 allow_signal(SIGKILL);
352 current->flags |= PF_MEMALLOC;
353 server->tsk = current; /* save process info to wake at shutdown */
354 cFYI(1, ("Demultiplex PID: %d", current->pid));
355 write_lock(&GlobalSMBSeslock);
356 atomic_inc(&tcpSesAllocCount);
357 length = tcpSesAllocCount.counter;
358 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700359 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 if(length > 1) {
361 mempool_resize(cifs_req_poolp,
362 length + cifs_min_rcv,
363 GFP_KERNEL);
364 }
365
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700366 set_freezable();
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000367 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700368 if (try_to_freeze())
369 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700370 if (bigbuf == NULL) {
371 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000372 if (!bigbuf) {
373 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700374 msleep(3000);
375 /* retry will check if exiting */
376 continue;
377 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000378 } else if (isLargeBuf) {
379 /* we are reusing a dirty large buf, clear its start */
Steve Frenchb8643e12005-04-28 22:41:07 -0700380 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700382
383 if (smallbuf == NULL) {
384 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000385 if (!smallbuf) {
386 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700387 msleep(1000);
388 /* retry will check if exiting */
389 continue;
390 }
391 /* beginning of smb buffer is cleared in our buf_get */
392 } else /* if existing small buf clear beginning */
393 memset(smallbuf, 0, sizeof (struct smb_hdr));
394
395 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700396 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700397 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 iov.iov_base = smb_buffer;
399 iov.iov_len = 4;
400 smb_msg.msg_control = NULL;
401 smb_msg.msg_controllen = 0;
402 length =
403 kernel_recvmsg(csocket, &smb_msg,
404 &iov, 1, 4, 0 /* BB see socket.h flags */);
405
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000406 if ( kthread_should_stop() ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 break;
408 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000409 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000411 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 csocket = server->ssocket;
413 continue;
414 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700415 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 allowing socket to clear and app threads to set
417 tcpStatus CifsNeedReconnect if server hung */
418 continue;
419 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000420 if (server->tcpStatus == CifsNew) {
421 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700422 /* some servers kill the TCP session rather than
423 returning an SMB negprot error, in which
424 case reconnecting here is not going to help,
425 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000428 if (!try_to_freeze() && (length == -EINTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 cFYI(1,("cifsd thread killed"));
430 break;
431 }
Steve French57337e42005-04-28 22:41:10 -0700432 cFYI(1,("Reconnect after unexpected peek error %d",
433 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 cifs_reconnect(server);
435 csocket = server->ssocket;
436 wake_up(&server->response_q);
437 continue;
Steve French46810cb2005-04-28 22:41:09 -0700438 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700440 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 length));
442 cifs_reconnect(server);
443 csocket = server->ssocket;
444 wake_up(&server->response_q);
445 continue;
446 }
Steve French67010fb2005-04-28 22:41:09 -0700447
Steve French70ca7342005-09-22 16:32:06 -0700448 /* The right amount was read from socket - 4 bytes */
449 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700450
Steve French70ca7342005-09-22 16:32:06 -0700451 /* the first byte big endian of the length field,
452 is actually not part of the length but the type
453 with the most common, zero, as regular data */
454 temp = *((char *) smb_buffer);
455
456 /* Note that FC 1001 length is big endian on the wire,
457 but we convert it here so it is always manipulated
458 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700459 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700460 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700461
Steve French70ca7342005-09-22 16:32:06 -0700462 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
463
464 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700465 continue;
Steve French70ca7342005-09-22 16:32:06 -0700466 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700467 cFYI(1,("Good RFC 1002 session rsp"));
468 continue;
Steve French70ca7342005-09-22 16:32:06 -0700469 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve French46810cb2005-04-28 22:41:09 -0700470 /* we get this from Windows 98 instead of
471 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700472 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700473 pdu_length));
Steve French46810cb2005-04-28 22:41:09 -0700474 if(server->tcpStatus == CifsNew) {
475 /* if nack on negprot (rather than
476 ret of smb negprot error) reconnecting
477 not going to help, ret error to mount */
478 break;
479 } else {
480 /* give server a second to
481 clean up before reconnect attempt */
482 msleep(1000);
483 /* always try 445 first on reconnect
484 since we get NACK on some if we ever
485 connected to port 139 (the NACK is
486 since we do not begin with RFC1001
487 session initialize frame) */
488 server->addr.sockAddr.sin_port =
489 htons(CIFS_PORT);
490 cifs_reconnect(server);
491 csocket = server->ssocket;
492 wake_up(&server->response_q);
493 continue;
494 }
Steve French70ca7342005-09-22 16:32:06 -0700495 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700496 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700497 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
498 length);
Steve French46810cb2005-04-28 22:41:09 -0700499 cifs_reconnect(server);
500 csocket = server->ssocket;
501 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700502 }
503
504 /* else we have an SMB response */
505 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700506 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700507 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700508 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700509 cifs_reconnect(server);
510 csocket = server->ssocket;
511 wake_up(&server->response_q);
512 continue;
513 }
514
515 /* else length ok */
516 reconnect = 0;
517
Steve Frenchec637e32005-12-12 20:53:18 -0800518 if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700519 isLargeBuf = TRUE;
520 memcpy(bigbuf, smallbuf, 4);
521 smb_buffer = bigbuf;
522 }
523 length = 0;
524 iov.iov_base = 4 + (char *)smb_buffer;
525 iov.iov_len = pdu_length;
526 for (total_read = 0; total_read < pdu_length;
527 total_read += length) {
528 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
529 pdu_length - total_read, 0);
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000530 if( kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 (length == -EINTR)) {
532 /* then will exit */
533 reconnect = 2;
534 break;
535 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700536 cifs_reconnect(server);
537 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700538 /* Reconnect wakes up rspns q */
539 /* Now we will reread sock */
540 reconnect = 1;
541 break;
542 } else if ((length == -ERESTARTSYS) ||
543 (length == -EAGAIN)) {
544 msleep(1); /* minimum sleep to prevent looping,
545 allowing socket to clear and app
546 threads to set tcpStatus
547 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700548 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700549 } else if (length <= 0) {
550 cERROR(1,("Received no data, expecting %d",
551 pdu_length - total_read));
552 cifs_reconnect(server);
553 csocket = server->ssocket;
554 reconnect = 1;
555 break;
Steve French46810cb2005-04-28 22:41:09 -0700556 }
557 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 if(reconnect == 2)
559 break;
560 else if(reconnect == 1)
561 continue;
562
563 length += 4; /* account for rfc1002 hdr */
564
565
566 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000567 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700568 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700569 continue;
570 }
571
572
573 task_to_wake = NULL;
574 spin_lock(&GlobalMid_Lock);
575 list_for_each(tmp, &server->pending_mid_q) {
576 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
577
578 if ((mid_entry->mid == smb_buffer->Mid) &&
579 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
580 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
582 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700583 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 if(mid_entry->resp_buf) {
585 /* merge response - fix up 1st*/
586 if(coalesce_t2(smb_buffer,
587 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000588 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 break;
590 } else {
591 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000592 mid_entry->multiEnd = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700593 goto multi_t2_fnd;
594 }
595 } else {
596 if(!isLargeBuf) {
597 cERROR(1,("1st trans2 resp needs bigbuf"));
598 /* BB maybe we can fix this up, switch
599 to already allocated large buffer? */
600 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700601 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700602 mid_entry->resp_buf =
603 smb_buffer;
604 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700605 bigbuf = NULL;
606 }
607 }
608 break;
609 }
610 mid_entry->resp_buf = smb_buffer;
611 if(isLargeBuf)
612 mid_entry->largeBuf = 1;
613 else
614 mid_entry->largeBuf = 0;
615multi_t2_fnd:
616 task_to_wake = mid_entry->tsk;
617 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700618#ifdef CONFIG_CIFS_STATS2
619 mid_entry->when_received = jiffies;
620#endif
Steve French3a5ff612006-07-14 22:37:11 +0000621 /* so we do not time out requests to server
622 which is still responding (since server could
623 be busy but not dead) */
624 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700625 break;
626 }
627 }
628 spin_unlock(&GlobalMid_Lock);
629 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700630 /* Was previous buf put in mpx struct for multi-rsp? */
631 if(!isMultiRsp) {
632 /* smb buffer will be freed by user thread */
633 if(isLargeBuf) {
634 bigbuf = NULL;
635 } else
636 smallbuf = NULL;
637 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700638 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000639 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700640 && (isMultiRsp == FALSE)) {
Steve French39798772006-05-31 22:40:51 +0000641 cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
Steve French70ca7342005-09-22 16:32:06 -0700642 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
643 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000644#ifdef CONFIG_CIFS_DEBUG2
645 cifs_dump_detail(smb_buffer);
646 cifs_dump_mids(server);
647#endif /* CIFS_DEBUG2 */
648
Steve Frenche4eb2952005-04-28 22:41:09 -0700649 }
650 } /* end while !EXITING */
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 spin_lock(&GlobalMid_Lock);
653 server->tcpStatus = CifsExiting;
654 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700655 /* check if we have blocked requests that need to free */
656 /* Note that cifs_max_pending is normally 50, but
657 can be set at module install time to as little as two */
658 if(atomic_read(&server->inFlight) >= cifs_max_pending)
659 atomic_set(&server->inFlight, cifs_max_pending - 1);
660 /* We do not want to set the max_pending too low or we
661 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 spin_unlock(&GlobalMid_Lock);
663 /* Although there should not be any requests blocked on
664 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700665 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 to the same server - they now will see the session is in exit state
667 and get out of SendReceive. */
668 wake_up_all(&server->request_q);
669 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700670 msleep(125);
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if(server->ssocket) {
673 sock_release(csocket);
674 server->ssocket = NULL;
675 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700676 /* buffer usuallly freed in free_mid - need to free it here on exit */
677 if (bigbuf != NULL)
678 cifs_buf_release(bigbuf);
679 if (smallbuf != NULL)
680 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 read_lock(&GlobalSMBSeslock);
683 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700684 /* loop through server session structures attached to this and
685 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 list_for_each(tmp, &GlobalSMBSessionList) {
687 ses =
688 list_entry(tmp, struct cifsSesInfo,
689 cifsSessionList);
690 if (ses->server == server) {
691 ses->status = CifsExiting;
692 ses->server = NULL;
693 }
694 }
695 read_unlock(&GlobalSMBSeslock);
696 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700697 /* although we can not zero the server struct pointer yet,
698 since there are active requests which may depnd on them,
699 mark the corresponding SMB sessions as exiting too */
700 list_for_each(tmp, &GlobalSMBSessionList) {
701 ses = list_entry(tmp, struct cifsSesInfo,
702 cifsSessionList);
703 if (ses->server == server) {
704 ses->status = CifsExiting;
705 }
706 }
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 spin_lock(&GlobalMid_Lock);
709 list_for_each(tmp, &server->pending_mid_q) {
710 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
711 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
712 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700713 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 task_to_wake = mid_entry->tsk;
715 if(task_to_wake) {
716 wake_up_process(task_to_wake);
717 }
718 }
719 }
720 spin_unlock(&GlobalMid_Lock);
721 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700723 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725
Steve Frenchf1914012005-08-18 09:37:34 -0700726 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 /* mpx threads have not exited yet give them
728 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700729 /* due to delays on oplock break requests, we need
730 to wait at least 45 seconds before giving up
731 on a request getting a response and going ahead
732 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700734 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /* if threads still have not exited they are probably never
736 coming home not much else we can do but free the memory */
737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 write_lock(&GlobalSMBSeslock);
740 atomic_dec(&tcpSesAllocCount);
741 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700742
743 /* last chance to mark ses pointers invalid
744 if there are any pointing to this (e.g
745 if a crazy root user tried to kill cifsd
746 kernel thread explicitly this might happen) */
747 list_for_each(tmp, &GlobalSMBSessionList) {
748 ses = list_entry(tmp, struct cifsSesInfo,
749 cifsSessionList);
750 if (ses->server == server) {
751 ses->server = NULL;
752 }
753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700755
756 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 if(length > 0) {
758 mempool_resize(cifs_req_poolp,
759 length + cifs_min_rcv,
760 GFP_KERNEL);
761 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return 0;
764}
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766static int
767cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
768{
769 char *value;
770 char *data;
771 unsigned int temp_len, i, j;
772 char separator[2];
773
774 separator[0] = ',';
775 separator[1] = 0;
776
Linus Torvalds12e36b22006-10-13 08:09:29 -0700777 if (Local_System_Name[0] != 0)
Steve French2cd646a2006-09-28 19:43:08 +0000778 memcpy(vol->source_rfc1001_name, Local_System_Name,15);
779 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700780 char *nodename = utsname()->nodename;
781 int n = strnlen(nodename,15);
Steve French2cd646a2006-09-28 19:43:08 +0000782 memset(vol->source_rfc1001_name,0x20,15);
Linus Torvalds12e36b22006-10-13 08:09:29 -0700783 for(i=0 ; i < n ; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000784 /* does not have to be perfect mapping since field is
785 informational, only used for servers that do not support
786 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700787 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700791 /* null target name indicates to use *SMBSERVR default called name
792 if we end up sending RFC1001 session initialize */
793 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 vol->linux_uid = current->uid; /* current->euid instead? */
795 vol->linux_gid = current->gid;
796 vol->dir_mode = S_IRWXUGO;
797 /* 2767 perms indicate mandatory locking support */
798 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
799
800 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
801 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700802 /* default is always to request posix paths. */
803 vol->posix_paths = 1;
804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 if (!options)
806 return 1;
807
808 if(strncmp(options,"sep=",4) == 0) {
809 if(options[4] != 0) {
810 separator[0] = options[4];
811 options += 5;
812 } else {
813 cFYI(1,("Null separator not allowed"));
814 }
815 }
816
817 while ((data = strsep(&options, separator)) != NULL) {
818 if (!*data)
819 continue;
820 if ((value = strchr(data, '=')) != NULL)
821 *value++ = '\0';
822
823 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
824 vol->no_xattr = 0;
825 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
826 vol->no_xattr = 1;
827 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000828 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 printk(KERN_WARNING
830 "CIFS: invalid or missing username\n");
831 return 1; /* needs_arg; */
Steve French4b952a92006-10-30 21:46:13 +0000832 } else if(!*value) {
833 /* null user, ie anonymous, authentication */
834 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 }
836 if (strnlen(value, 200) < 200) {
837 vol->username = value;
838 } else {
839 printk(KERN_WARNING "CIFS: username too long\n");
840 return 1;
841 }
842 } else if (strnicmp(data, "pass", 4) == 0) {
843 if (!value) {
844 vol->password = NULL;
845 continue;
846 } else if(value[0] == 0) {
847 /* check if string begins with double comma
848 since that would mean the password really
849 does start with a comma, and would not
850 indicate an empty string */
851 if(value[1] != separator[0]) {
852 vol->password = NULL;
853 continue;
854 }
855 }
856 temp_len = strlen(value);
857 /* removed password length check, NTLM passwords
858 can be arbitrarily long */
859
860 /* if comma in password, the string will be
861 prematurely null terminated. Commas in password are
862 specified across the cifs mount interface by a double
863 comma ie ,, and a comma used as in other cases ie ','
864 as a parameter delimiter/separator is single and due
865 to the strsep above is temporarily zeroed. */
866
867 /* NB: password legally can have multiple commas and
868 the only illegal character in a password is null */
869
Steve French09d1db52005-04-28 22:41:08 -0700870 if ((value[temp_len] == 0) &&
871 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 /* reinsert comma */
873 value[temp_len] = separator[0];
874 temp_len+=2; /* move after the second comma */
875 while(value[temp_len] != 0) {
876 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700877 if (value[temp_len+1] ==
878 separator[0]) {
879 /* skip second comma */
880 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 } else {
882 /* single comma indicating start
883 of next parm */
884 break;
885 }
886 }
887 temp_len++;
888 }
889 if(value[temp_len] == 0) {
890 options = NULL;
891 } else {
892 value[temp_len] = 0;
893 /* point option to start of next parm */
894 options = value + temp_len + 1;
895 }
896 /* go from value to value + temp_len condensing
897 double commas to singles. Note that this ends up
898 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700899 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700900 if(vol->password == NULL) {
901 printk("CIFS: no memory for pass\n");
902 return 1;
903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 for(i=0,j=0;i<temp_len;i++,j++) {
905 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700906 if(value[i] == separator[0]
907 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 /* skip second comma */
909 i++;
910 }
911 }
912 vol->password[j] = 0;
913 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700914 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700915 if(vol->password == NULL) {
916 printk("CIFS: no memory for pass\n");
917 return 1;
918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 strcpy(vol->password, value);
920 }
921 } else if (strnicmp(data, "ip", 2) == 0) {
922 if (!value || !*value) {
923 vol->UNCip = NULL;
924 } else if (strnlen(value, 35) < 35) {
925 vol->UNCip = value;
926 } else {
927 printk(KERN_WARNING "CIFS: ip address too long\n");
928 return 1;
929 }
Steve Frenchbf820672005-12-01 22:32:42 -0800930 } else if (strnicmp(data, "sec", 3) == 0) {
931 if (!value || !*value) {
932 cERROR(1,("no security value specified"));
933 continue;
934 } else if (strnicmp(value, "krb5i", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000935 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000936 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800937 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000938 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
Steve French189acaa2006-06-23 02:33:48 +0000939 CIFSSEC_MAY_KRB5; */
Steve Frenchbf820672005-12-01 22:32:42 -0800940 cERROR(1,("Krb5 cifs privacy not supported"));
941 return 1;
942 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000943 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800944 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000945 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000946 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800947 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000948 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800949 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000950 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000951 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800952 } else if (strnicmp(value, "ntlm", 4) == 0) {
953 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000954 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800955 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000956 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000957 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000958#ifdef CONFIG_CIFS_WEAK_PW_HASH
959 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000960 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000961#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800962 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000963 vol->nullauth = 1;
Steve Frenchbf820672005-12-01 22:32:42 -0800964 } else {
965 cERROR(1,("bad security option: %s", value));
966 return 1;
967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 } else if ((strnicmp(data, "unc", 3) == 0)
969 || (strnicmp(data, "target", 6) == 0)
970 || (strnicmp(data, "path", 4) == 0)) {
971 if (!value || !*value) {
972 printk(KERN_WARNING
973 "CIFS: invalid path to network resource\n");
974 return 1; /* needs_arg; */
975 }
976 if ((temp_len = strnlen(value, 300)) < 300) {
977 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000978 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return 1;
980 strcpy(vol->UNC,value);
981 if (strncmp(vol->UNC, "//", 2) == 0) {
982 vol->UNC[0] = '\\';
983 vol->UNC[1] = '\\';
984 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
985 printk(KERN_WARNING
986 "CIFS: UNC Path does not begin with // or \\\\ \n");
987 return 1;
988 }
989 } else {
990 printk(KERN_WARNING "CIFS: UNC name too long\n");
991 return 1;
992 }
993 } else if ((strnicmp(data, "domain", 3) == 0)
994 || (strnicmp(data, "workgroup", 5) == 0)) {
995 if (!value || !*value) {
996 printk(KERN_WARNING "CIFS: invalid domain name\n");
997 return 1; /* needs_arg; */
998 }
999 /* BB are there cases in which a comma can be valid in
1000 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001001 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 vol->domainname = value;
1003 cFYI(1, ("Domain name set"));
1004 } else {
1005 printk(KERN_WARNING "CIFS: domain name too long\n");
1006 return 1;
1007 }
Steve French2fe87f02006-09-21 07:02:52 +00001008 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1009 if (!value || !*value) {
1010 printk(KERN_WARNING
1011 "CIFS: invalid path prefix\n");
1012 return 1; /* needs_arg; */
1013 }
1014 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001015 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001016 temp_len++; /* missing leading slash */
1017 vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001018 if (vol->prepath == NULL)
Steve French2fe87f02006-09-21 07:02:52 +00001019 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001020 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001021 vol->prepath[0] = '/';
1022 strcpy(vol->prepath+1,value);
1023 } else
1024 strcpy(vol->prepath,value);
1025 cFYI(1,("prefix path %s",vol->prepath));
1026 } else {
1027 printk(KERN_WARNING "CIFS: prefix too long\n");
1028 return 1;
1029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 } else if (strnicmp(data, "iocharset", 9) == 0) {
1031 if (!value || !*value) {
1032 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
1033 return 1; /* needs_arg; */
1034 }
1035 if (strnlen(value, 65) < 65) {
Steve French4523cc32007-04-30 20:13:06 +00001036 if (strnicmp(value,"default",7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 vol->iocharset = value;
1038 /* if iocharset not set load_nls_default used by caller */
1039 cFYI(1, ("iocharset set to %s",value));
1040 } else {
1041 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
1042 return 1;
1043 }
1044 } else if (strnicmp(data, "uid", 3) == 0) {
1045 if (value && *value) {
1046 vol->linux_uid =
1047 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001048 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 }
1050 } else if (strnicmp(data, "gid", 3) == 0) {
1051 if (value && *value) {
1052 vol->linux_gid =
1053 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001054 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 }
1056 } else if (strnicmp(data, "file_mode", 4) == 0) {
1057 if (value && *value) {
1058 vol->file_mode =
1059 simple_strtoul(value, &value, 0);
1060 }
1061 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1062 if (value && *value) {
1063 vol->dir_mode =
1064 simple_strtoul(value, &value, 0);
1065 }
1066 } else if (strnicmp(data, "dirmode", 4) == 0) {
1067 if (value && *value) {
1068 vol->dir_mode =
1069 simple_strtoul(value, &value, 0);
1070 }
1071 } else if (strnicmp(data, "port", 4) == 0) {
1072 if (value && *value) {
1073 vol->port =
1074 simple_strtoul(value, &value, 0);
1075 }
1076 } else if (strnicmp(data, "rsize", 5) == 0) {
1077 if (value && *value) {
1078 vol->rsize =
1079 simple_strtoul(value, &value, 0);
1080 }
1081 } else if (strnicmp(data, "wsize", 5) == 0) {
1082 if (value && *value) {
1083 vol->wsize =
1084 simple_strtoul(value, &value, 0);
1085 }
1086 } else if (strnicmp(data, "sockopt", 5) == 0) {
1087 if (value && *value) {
1088 vol->sockopt =
1089 simple_strtoul(value, &value, 0);
1090 }
1091 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1092 if (!value || !*value || (*value == ' ')) {
1093 cFYI(1,("invalid (empty) netbiosname specified"));
1094 } else {
1095 memset(vol->source_rfc1001_name,0x20,15);
1096 for(i=0;i<15;i++) {
1097 /* BB are there cases in which a comma can be
1098 valid in this workstation netbios name (and need
1099 special handling)? */
1100
1101 /* We do not uppercase netbiosname for user */
1102 if (value[i]==0)
1103 break;
1104 else
1105 vol->source_rfc1001_name[i] = value[i];
1106 }
1107 /* The string has 16th byte zero still from
1108 set at top of the function */
Steve French4523cc32007-04-30 20:13:06 +00001109 if ((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001110 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1111 }
1112 } else if (strnicmp(data, "servern", 7) == 0) {
1113 /* servernetbiosname specified override *SMBSERVER */
1114 if (!value || !*value || (*value == ' ')) {
1115 cFYI(1,("empty server netbiosname specified"));
1116 } else {
1117 /* last byte, type, is 0x20 for servr type */
1118 memset(vol->target_rfc1001_name,0x20,16);
1119
1120 for(i=0;i<15;i++) {
1121 /* BB are there cases in which a comma can be
1122 valid in this workstation netbios name (and need
1123 special handling)? */
1124
1125 /* user or mount helper must uppercase netbiosname */
1126 if (value[i]==0)
1127 break;
1128 else
1129 vol->target_rfc1001_name[i] = value[i];
1130 }
1131 /* The string has 16th byte zero still from
1132 set at top of the function */
Steve French4523cc32007-04-30 20:13:06 +00001133 if ((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001134 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 }
1136 } else if (strnicmp(data, "credentials", 4) == 0) {
1137 /* ignore */
1138 } else if (strnicmp(data, "version", 3) == 0) {
1139 /* ignore */
1140 } else if (strnicmp(data, "guest",5) == 0) {
1141 /* ignore */
1142 } else if (strnicmp(data, "rw", 2) == 0) {
1143 vol->rw = TRUE;
1144 } else if ((strnicmp(data, "suid", 4) == 0) ||
1145 (strnicmp(data, "nosuid", 6) == 0) ||
1146 (strnicmp(data, "exec", 4) == 0) ||
1147 (strnicmp(data, "noexec", 6) == 0) ||
1148 (strnicmp(data, "nodev", 5) == 0) ||
1149 (strnicmp(data, "noauto", 6) == 0) ||
1150 (strnicmp(data, "dev", 3) == 0)) {
1151 /* The mount tool or mount.cifs helper (if present)
1152 uses these opts to set flags, and the flags are read
1153 by the kernel vfs layer before we get here (ie
1154 before read super) so there is no point trying to
1155 parse these options again and set anything and it
1156 is ok to just ignore them */
1157 continue;
1158 } else if (strnicmp(data, "ro", 2) == 0) {
1159 vol->rw = FALSE;
1160 } else if (strnicmp(data, "hard", 4) == 0) {
1161 vol->retry = 1;
1162 } else if (strnicmp(data, "soft", 4) == 0) {
1163 vol->retry = 0;
1164 } else if (strnicmp(data, "perm", 4) == 0) {
1165 vol->noperm = 0;
1166 } else if (strnicmp(data, "noperm", 6) == 0) {
1167 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001168 } else if (strnicmp(data, "mapchars", 8) == 0) {
1169 vol->remap = 1;
1170 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1171 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001172 } else if (strnicmp(data, "sfu", 3) == 0) {
1173 vol->sfu_emul = 1;
1174 } else if (strnicmp(data, "nosfu", 5) == 0) {
1175 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001176 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1177 vol->posix_paths = 1;
1178 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1179 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001180 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1181 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001182 vol->nocase = 1;
1183 } else if (strnicmp(data, "brl", 3) == 0) {
1184 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001185 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001186 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001187 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001188 /* turn off mandatory locking in mode
1189 if remote locking is turned off since the
1190 local vfs will do advisory */
1191 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1192 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 } else if (strnicmp(data, "setuids", 7) == 0) {
1194 vol->setuids = 1;
1195 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1196 vol->setuids = 0;
1197 } else if (strnicmp(data, "nohard", 6) == 0) {
1198 vol->retry = 0;
1199 } else if (strnicmp(data, "nosoft", 6) == 0) {
1200 vol->retry = 1;
1201 } else if (strnicmp(data, "nointr", 6) == 0) {
1202 vol->intr = 0;
1203 } else if (strnicmp(data, "intr", 4) == 0) {
1204 vol->intr = 1;
1205 } else if (strnicmp(data, "serverino",7) == 0) {
1206 vol->server_ino = 1;
1207 } else if (strnicmp(data, "noserverino",9) == 0) {
1208 vol->server_ino = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08001209 } else if (strnicmp(data, "cifsacl",7) == 0) {
1210 vol->cifs_acl = 1;
1211 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1212 vol->cifs_acl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 } else if (strnicmp(data, "acl",3) == 0) {
1214 vol->no_psx_acl = 0;
1215 } else if (strnicmp(data, "noacl",5) == 0) {
1216 vol->no_psx_acl = 1;
Steve French750d1152006-06-27 06:28:30 +00001217 } else if (strnicmp(data, "sign",4) == 0) {
1218 vol->secFlg |= CIFSSEC_MUST_SIGN;
1219/* } else if (strnicmp(data, "seal",4) == 0) {
1220 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 } else if (strnicmp(data, "direct",6) == 0) {
1222 vol->direct_io = 1;
1223 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1224 vol->direct_io = 1;
1225 } else if (strnicmp(data, "in6_addr",8) == 0) {
1226 if (!value || !*value) {
1227 vol->in6_addr = NULL;
1228 } else if (strnlen(value, 49) == 48) {
1229 vol->in6_addr = value;
1230 } else {
1231 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1232 return 1;
1233 }
1234 } else if (strnicmp(data, "noac", 4) == 0) {
1235 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1236 } else
1237 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1238 }
1239 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001240 if (devname == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1242 return 1;
1243 }
1244 if ((temp_len = strnlen(devname, 300)) < 300) {
1245 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001246 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 return 1;
1248 strcpy(vol->UNC,devname);
1249 if (strncmp(vol->UNC, "//", 2) == 0) {
1250 vol->UNC[0] = '\\';
1251 vol->UNC[1] = '\\';
1252 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1253 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1254 return 1;
1255 }
1256 } else {
1257 printk(KERN_WARNING "CIFS: UNC name too long\n");
1258 return 1;
1259 }
1260 }
1261 if(vol->UNCip == NULL)
1262 vol->UNCip = &vol->UNC[2];
1263
1264 return 0;
1265}
1266
1267static struct cifsSesInfo *
1268cifs_find_tcp_session(struct in_addr * target_ip_addr,
1269 struct in6_addr *target_ip6_addr,
1270 char *userName, struct TCP_Server_Info **psrvTcp)
1271{
1272 struct list_head *tmp;
1273 struct cifsSesInfo *ses;
1274 *psrvTcp = NULL;
1275 read_lock(&GlobalSMBSeslock);
1276
1277 list_for_each(tmp, &GlobalSMBSessionList) {
1278 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1279 if (ses->server) {
1280 if((target_ip_addr &&
1281 (ses->server->addr.sockAddr.sin_addr.s_addr
1282 == target_ip_addr->s_addr)) || (target_ip6_addr
1283 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1284 target_ip6_addr,sizeof(*target_ip6_addr)))){
1285 /* BB lock server and tcp session and increment use count here?? */
1286 *psrvTcp = ses->server; /* found a match on the TCP session */
1287 /* BB check if reconnection needed */
1288 if (strncmp
1289 (ses->userName, userName,
1290 MAX_USERNAME_SIZE) == 0){
1291 read_unlock(&GlobalSMBSeslock);
1292 return ses; /* found exact match on both tcp and SMB sessions */
1293 }
1294 }
1295 }
1296 /* else tcp and smb sessions need reconnection */
1297 }
1298 read_unlock(&GlobalSMBSeslock);
1299 return NULL;
1300}
1301
1302static struct cifsTconInfo *
1303find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1304{
1305 struct list_head *tmp;
1306 struct cifsTconInfo *tcon;
1307
1308 read_lock(&GlobalSMBSeslock);
1309 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001310 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1312 if (tcon->ses) {
1313 if (tcon->ses->server) {
1314 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001315 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 tcon->ses->server->addr.sockAddr.sin_addr.
1317 s_addr, new_target_ip_addr));
1318 if (tcon->ses->server->addr.sockAddr.sin_addr.
1319 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001320 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 /* found a match on the TCP session */
1322 /* BB check if reconnection needed */
Steve Frenche466e482006-08-15 13:07:18 +00001323 cFYI(1,("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 tcon->treeName, uncName));
1325 if (strncmp
1326 (tcon->treeName, uncName,
1327 MAX_TREE_SIZE) == 0) {
1328 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001329 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 tcon->treeName, uncName));
1331 if (strncmp
1332 (tcon->ses->userName,
1333 userName,
1334 MAX_USERNAME_SIZE) == 0) {
1335 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001336 /* matched smb session
1337 (user name */
1338 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 }
1340 }
1341 }
1342 }
1343 }
1344 }
1345 read_unlock(&GlobalSMBSeslock);
1346 return NULL;
1347}
1348
1349int
1350connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001351 const char *old_path, const struct nls_table *nls_codepage,
1352 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353{
1354 unsigned char *referrals = NULL;
1355 unsigned int num_referrals;
1356 int rc = 0;
1357
1358 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001359 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 /* BB Add in code to: if valid refrl, if not ip address contact
1362 the helper that resolves tcp names, mount to it, try to
1363 tcon to it unmount it if fail */
1364
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001365 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
1367 return rc;
1368}
1369
1370int
1371get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1372 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001373 unsigned int *pnum_referrals,
1374 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375{
1376 char *temp_unc;
1377 int rc = 0;
1378
1379 *pnum_referrals = 0;
1380
1381 if (pSesInfo->ipc_tid == 0) {
1382 temp_unc = kmalloc(2 /* for slashes */ +
1383 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1384 + 1 + 4 /* slash IPC$ */ + 2,
1385 GFP_KERNEL);
1386 if (temp_unc == NULL)
1387 return -ENOMEM;
1388 temp_unc[0] = '\\';
1389 temp_unc[1] = '\\';
1390 strcpy(temp_unc + 2, pSesInfo->serverName);
1391 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1392 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1393 cFYI(1,
1394 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1395 kfree(temp_unc);
1396 }
1397 if (rc == 0)
1398 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001399 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
1401 return rc;
1402}
1403
1404/* See RFC1001 section 14 on representation of Netbios names */
1405static void rfc1002mangle(char * target,char * source, unsigned int length)
1406{
1407 unsigned int i,j;
1408
1409 for(i=0,j=0;i<(length);i++) {
1410 /* mask a nibble at a time and encode */
1411 target[j] = 'A' + (0x0F & (source[i] >> 4));
1412 target[j+1] = 'A' + (0x0F & source[i]);
1413 j+=2;
1414 }
1415
1416}
1417
1418
1419static int
1420ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001421 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422{
1423 int rc = 0;
1424 int connected = 0;
1425 __be16 orig_port = 0;
1426
1427 if(*csocket == NULL) {
1428 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1429 if (rc < 0) {
1430 cERROR(1, ("Error %d creating socket",rc));
1431 *csocket = NULL;
1432 return rc;
1433 } else {
1434 /* BB other socket options to set KEEPALIVE, NODELAY? */
1435 cFYI(1,("Socket created"));
1436 (*csocket)->sk->sk_allocation = GFP_NOFS;
1437 }
1438 }
1439
1440 psin_server->sin_family = AF_INET;
1441 if(psin_server->sin_port) { /* user overrode default port */
1442 rc = (*csocket)->ops->connect(*csocket,
1443 (struct sockaddr *) psin_server,
1444 sizeof (struct sockaddr_in),0);
1445 if (rc >= 0)
1446 connected = 1;
1447 }
1448
1449 if(!connected) {
1450 /* save original port so we can retry user specified port
1451 later if fall back ports fail this time */
1452 orig_port = psin_server->sin_port;
1453
1454 /* do not retry on the same port we just failed on */
1455 if(psin_server->sin_port != htons(CIFS_PORT)) {
1456 psin_server->sin_port = htons(CIFS_PORT);
1457
1458 rc = (*csocket)->ops->connect(*csocket,
1459 (struct sockaddr *) psin_server,
1460 sizeof (struct sockaddr_in),0);
1461 if (rc >= 0)
1462 connected = 1;
1463 }
1464 }
1465 if (!connected) {
1466 psin_server->sin_port = htons(RFC1001_PORT);
1467 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1468 psin_server, sizeof (struct sockaddr_in),0);
1469 if (rc >= 0)
1470 connected = 1;
1471 }
1472
1473 /* give up here - unless we want to retry on different
1474 protocol families some day */
1475 if (!connected) {
1476 if(orig_port)
1477 psin_server->sin_port = orig_port;
1478 cFYI(1,("Error %d connecting to server via ipv4",rc));
1479 sock_release(*csocket);
1480 *csocket = NULL;
1481 return rc;
1482 }
1483 /* Eventually check for other socket options to change from
1484 the default. sock_setsockopt not used because it expects
1485 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001486 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1487 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001489 /* make the bufsizes depend on wsize/rsize and max requests */
1490 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1491 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1492 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1493 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
1495 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1497 /* some servers require RFC1001 sessinit before sending
1498 negprot - BB check reconnection in case where second
1499 sessinit is sent but no second negprot */
1500 struct rfc1002_session_packet * ses_init_buf;
1501 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001502 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if(ses_init_buf) {
1504 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001505 if(target_name && (target_name[0] != 0)) {
1506 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1507 target_name, 16);
1508 } else {
1509 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1510 DEFAULT_CIFS_CALLED_NAME,16);
1511 }
1512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 ses_init_buf->trailer.session_req.calling_len = 32;
1514 /* calling name ends in null (byte 16) from old smb
1515 convention. */
1516 if(netbios_name && (netbios_name[0] !=0)) {
1517 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1518 netbios_name,16);
1519 } else {
1520 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1521 "LINUX_CIFS_CLNT",16);
1522 }
1523 ses_init_buf->trailer.session_req.scope1 = 0;
1524 ses_init_buf->trailer.session_req.scope2 = 0;
1525 smb_buf = (struct smb_hdr *)ses_init_buf;
1526 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1527 smb_buf->smb_buf_length = 0x81000044;
1528 rc = smb_send(*csocket, smb_buf, 0x44,
1529 (struct sockaddr *)psin_server);
1530 kfree(ses_init_buf);
Steve French083d3a22006-03-03 09:53:36 +00001531 msleep(1); /* RFC1001 layer in at least one server
1532 requires very short break before negprot
1533 presumably because not expecting negprot
1534 to follow so fast. This is a simple
1535 solution that works without
1536 complicating the code and causes no
1537 significant slowing down on mount
1538 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 }
1540 /* else the negprot may still work without this
1541 even though malloc failed */
1542
1543 }
1544
1545 return rc;
1546}
1547
1548static int
1549ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1550{
1551 int rc = 0;
1552 int connected = 0;
1553 __be16 orig_port = 0;
1554
1555 if(*csocket == NULL) {
1556 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1557 if (rc < 0) {
1558 cERROR(1, ("Error %d creating ipv6 socket",rc));
1559 *csocket = NULL;
1560 return rc;
1561 } else {
1562 /* BB other socket options to set KEEPALIVE, NODELAY? */
1563 cFYI(1,("ipv6 Socket created"));
1564 (*csocket)->sk->sk_allocation = GFP_NOFS;
1565 }
1566 }
1567
1568 psin_server->sin6_family = AF_INET6;
1569
1570 if(psin_server->sin6_port) { /* user overrode default port */
1571 rc = (*csocket)->ops->connect(*csocket,
1572 (struct sockaddr *) psin_server,
1573 sizeof (struct sockaddr_in6),0);
1574 if (rc >= 0)
1575 connected = 1;
1576 }
1577
1578 if(!connected) {
1579 /* save original port so we can retry user specified port
1580 later if fall back ports fail this time */
1581
1582 orig_port = psin_server->sin6_port;
1583 /* do not retry on the same port we just failed on */
1584 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1585 psin_server->sin6_port = htons(CIFS_PORT);
1586
1587 rc = (*csocket)->ops->connect(*csocket,
1588 (struct sockaddr *) psin_server,
1589 sizeof (struct sockaddr_in6),0);
1590 if (rc >= 0)
1591 connected = 1;
1592 }
1593 }
1594 if (!connected) {
1595 psin_server->sin6_port = htons(RFC1001_PORT);
1596 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1597 psin_server, sizeof (struct sockaddr_in6),0);
1598 if (rc >= 0)
1599 connected = 1;
1600 }
1601
1602 /* give up here - unless we want to retry on different
1603 protocol families some day */
1604 if (!connected) {
1605 if(orig_port)
1606 psin_server->sin6_port = orig_port;
1607 cFYI(1,("Error %d connecting to server via ipv6",rc));
1608 sock_release(*csocket);
1609 *csocket = NULL;
1610 return rc;
1611 }
1612 /* Eventually check for other socket options to change from
1613 the default. sock_setsockopt not used because it expects
1614 user space buffer */
1615 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1616
1617 return rc;
1618}
1619
Steve French8af18972007-02-14 04:42:51 +00001620void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
1621 struct super_block * sb, struct smb_vol * vol_info)
1622{
1623 /* if we are reconnecting then should we check to see if
1624 * any requested capabilities changed locally e.g. via
1625 * remount but we can not do much about it here
1626 * if they have (even if we could detect it by the following)
1627 * Perhaps we could add a backpointer to array of sb from tcon
1628 * or if we change to make all sb to same share the same
1629 * sb as NFS - then we only have one backpointer to sb.
1630 * What if we wanted to mount the server share twice once with
1631 * and once without posixacls or posix paths? */
1632 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
1633
1634
1635 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
1636 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
1637
1638 /* check for reconnect case in which we do not
1639 want to change the mount behavior if we can avoid it */
1640 if(vol_info == NULL) {
1641 /* turn off POSIX ACL and PATHNAMES if not set
1642 originally at mount time */
1643 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1644 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1645 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1646 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
1647
1648
1649
1650
1651 }
1652
1653 cap &= CIFS_UNIX_CAP_MASK;
1654 if(vol_info && vol_info->no_psx_acl)
1655 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1656 else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
1657 cFYI(1,("negotiated posix acl support"));
1658 if(sb)
1659 sb->s_flags |= MS_POSIXACL;
1660 }
1661
1662 if(vol_info && vol_info->posix_paths == 0)
1663 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
1664 else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
1665 cFYI(1,("negotiate posix pathnames"));
1666 if(sb)
1667 CIFS_SB(sb)->mnt_cifs_flags |=
1668 CIFS_MOUNT_POSIX_PATHS;
1669 }
Steve French984acfe2007-04-26 16:42:50 +00001670
1671 /* We might be setting the path sep back to a different
1672 form if we are reconnecting and the server switched its
1673 posix path capability for this share */
Steve French0b2365f2007-05-03 04:30:13 +00001674 if(sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001675 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
1676
Steve French8af18972007-02-14 04:42:51 +00001677 cFYI(1,("Negotiate caps 0x%x",(int)cap));
1678#ifdef CONFIG_CIFS_DEBUG2
1679 if(cap & CIFS_UNIX_FCNTL_CAP)
1680 cFYI(1,("FCNTL cap"));
1681 if(cap & CIFS_UNIX_EXTATTR_CAP)
1682 cFYI(1,("EXTATTR cap"));
1683 if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1684 cFYI(1,("POSIX path cap"));
1685 if(cap & CIFS_UNIX_XATTR_CAP)
1686 cFYI(1,("XATTR cap"));
1687 if(cap & CIFS_UNIX_POSIX_ACL_CAP)
1688 cFYI(1,("POSIX ACL cap"));
1689#endif /* CIFS_DEBUG2 */
1690 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
1691 cFYI(1,("setting capabilities failed"));
1692 }
1693 }
1694}
1695
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696int
1697cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1698 char *mount_data, const char *devname)
1699{
1700 int rc = 0;
1701 int xid;
1702 int address_type = AF_INET;
1703 struct socket *csocket = NULL;
1704 struct sockaddr_in sin_server;
1705 struct sockaddr_in6 sin_server6;
1706 struct smb_vol volume_info;
1707 struct cifsSesInfo *pSesInfo = NULL;
1708 struct cifsSesInfo *existingCifsSes = NULL;
1709 struct cifsTconInfo *tcon = NULL;
1710 struct TCP_Server_Info *srvTcp = NULL;
1711
1712 xid = GetXid();
1713
1714/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1715
1716 memset(&volume_info,0,sizeof(struct smb_vol));
1717 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001718 kfree(volume_info.UNC);
1719 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001720 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 FreeXid(xid);
1722 return -EINVAL;
1723 }
1724
Jeff Layton8426c392007-05-05 03:27:49 +00001725 if (volume_info.nullauth) {
1726 cFYI(1,("null user"));
1727 volume_info.username = NULL;
1728 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 /* BB fixme parse for domain name here */
1730 cFYI(1, ("Username: %s ", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001732 cifserror("No username specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 /* In userspace mount helper we can get user name from alternate
1734 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001735 kfree(volume_info.UNC);
1736 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001737 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 FreeXid(xid);
1739 return -EINVAL;
1740 }
1741
1742 if (volume_info.UNCip && volume_info.UNC) {
1743 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1744
1745 if(rc <= 0) {
1746 /* not ipv4 address, try ipv6 */
1747 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1748 if(rc > 0)
1749 address_type = AF_INET6;
1750 } else {
1751 address_type = AF_INET;
1752 }
1753
1754 if(rc <= 0) {
1755 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001756 kfree(volume_info.UNC);
1757 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001758 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 FreeXid(xid);
1760 return -EINVAL;
1761 }
1762
1763 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1764 /* success */
1765 rc = 0;
1766 } else if (volume_info.UNCip){
1767 /* BB using ip addr as server name connect to the DFS root below */
1768 cERROR(1,("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001769 kfree(volume_info.UNC);
1770 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001771 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 FreeXid(xid);
1773 return -EINVAL;
1774 } else /* which servers DFS root would we conect to */ {
1775 cERROR(1,
Steve Frenchbf820672005-12-01 22:32:42 -08001776 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001777 kfree(volume_info.UNC);
1778 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001779 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 FreeXid(xid);
1781 return -EINVAL;
1782 }
1783
1784 /* this is needed for ASCII cp to Unicode converts */
1785 if(volume_info.iocharset == NULL) {
1786 cifs_sb->local_nls = load_nls_default();
1787 /* load_nls_default can not return null */
1788 } else {
1789 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1790 if(cifs_sb->local_nls == NULL) {
1791 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001792 kfree(volume_info.UNC);
1793 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001794 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 FreeXid(xid);
1796 return -ELIBACC;
1797 }
1798 }
1799
1800 if(address_type == AF_INET)
1801 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1802 NULL /* no ipv6 addr */,
1803 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001804 else if(address_type == AF_INET6) {
1805 cFYI(1,("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1807 &sin_server6.sin6_addr,
1808 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001809 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001810 kfree(volume_info.UNC);
1811 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001812 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 FreeXid(xid);
1814 return -EINVAL;
1815 }
1816
1817
1818 if (srvTcp) {
Steve Frenchbf820672005-12-01 22:32:42 -08001819 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001821 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 sin_server.sin_port = htons(volume_info.port);
1823 else
1824 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001825 if (address_type == AF_INET6) {
1826 cFYI(1,("attempting ipv6 connect"));
1827 /* BB should we allow ipv6 on port 139? */
1828 /* other OS never observed in Wild doing 139 with v6 */
1829 rc = ipv6_connect(&sin_server6,&csocket);
1830 } else
1831 rc = ipv4_connect(&sin_server,&csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001832 volume_info.source_rfc1001_name,
1833 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 if (rc < 0) {
1835 cERROR(1,
Steve French5858ae42007-04-25 11:59:10 +00001836 ("Error connecting to IPv4 socket. Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001837 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001839 kfree(volume_info.UNC);
1840 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001841 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 FreeXid(xid);
1843 return rc;
1844 }
1845
1846 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1847 if (srvTcp == NULL) {
1848 rc = -ENOMEM;
1849 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001850 kfree(volume_info.UNC);
1851 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001852 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 FreeXid(xid);
1854 return rc;
1855 } else {
1856 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1857 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1858 atomic_set(&srvTcp->inFlight,0);
1859 /* BB Add code for ipv6 case too */
1860 srvTcp->ssocket = csocket;
1861 srvTcp->protocolType = IPV4;
1862 init_waitqueue_head(&srvTcp->response_q);
1863 init_waitqueue_head(&srvTcp->request_q);
1864 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1865 /* at this point we are the only ones with the pointer
1866 to the struct since the kernel thread not created yet
1867 so no need to spinlock this init of tcpStatus */
1868 srvTcp->tcpStatus = CifsNew;
1869 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001870 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001871 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001872 rc = PTR_ERR(srvTcp->tsk);
1873 cERROR(1,("error %d create cifsd thread", rc));
1874 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001876 kfree(volume_info.UNC);
1877 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001878 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 FreeXid(xid);
1880 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001881 }
1882 wait_for_completion(&cifsd_complete);
1883 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001885 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001886 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 }
1888 }
1889
1890 if (existingCifsSes) {
1891 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001892 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001893 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 /* volume_info.UNC freed at end of function */
1895 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001896 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 pSesInfo = sesInfoAlloc();
1898 if (pSesInfo == NULL)
1899 rc = -ENOMEM;
1900 else {
1901 pSesInfo->server = srvTcp;
1902 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1903 NIPQUAD(sin_server.sin_addr.s_addr));
1904 }
1905
1906 if (!rc){
1907 /* volume_info.password freed at unmount */
1908 if (volume_info.password)
1909 pSesInfo->password = volume_info.password;
1910 if (volume_info.username)
1911 strncpy(pSesInfo->userName,
1912 volume_info.username,MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001913 if (volume_info.domainname) {
1914 int len = strlen(volume_info.domainname);
1915 pSesInfo->domainName =
1916 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001917 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001918 strcpy(pSesInfo->domainName,
1919 volume_info.domainname);
1920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001922 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001924 /* BB FIXME need to pass vol->secFlgs BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1926 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001927 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 atomic_inc(&srvTcp->socketUseCount);
1929 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001930 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 }
1932
1933 /* search for existing tcon to this server share */
1934 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00001935 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French0ae0efa2005-10-10 10:57:19 -07001936 cERROR(1,("rsize %d too large, using MaxBufSize",
1937 volume_info.rsize));
1938 cifs_sb->rsize = CIFSMaxBufSize;
1939 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001941 else /* default */
1942 cifs_sb->rsize = CIFSMaxBufSize;
1943
Steve French4523cc32007-04-30 20:13:06 +00001944 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French0ae0efa2005-10-10 10:57:19 -07001945 cERROR(1,("wsize %d too large using 4096 instead",
1946 volume_info.wsize));
1947 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00001948 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 cifs_sb->wsize = volume_info.wsize;
1950 else
Steve French17cbbaf2006-01-24 20:26:48 -08001951 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08001952 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1953 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08001954 /* old default of CIFSMaxBufSize was too small now
1955 that SMB Write2 can send multiple pages in kvec.
1956 RFC1001 does not describe what happens when frame
1957 bigger than 128K is sent so use that as max in
1958 conjunction with 52K kvec constraint on arch with 4K
1959 page size */
1960
Steve French4523cc32007-04-30 20:13:06 +00001961 if (cifs_sb->rsize < 2048) {
Steve French6cec2ae2006-02-22 17:31:52 -06001962 cifs_sb->rsize = 2048;
1963 /* Windows ME may prefer this */
1964 cFYI(1,("readsize set to minimum 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
Steve French2fe87f02006-09-21 07:02:52 +00001966 /* calculate prepath */
1967 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00001968 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00001969 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
1970 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
1971 volume_info.prepath = NULL;
1972 } else
1973 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 cifs_sb->mnt_uid = volume_info.linux_uid;
1975 cifs_sb->mnt_gid = volume_info.linux_gid;
1976 cifs_sb->mnt_file_mode = volume_info.file_mode;
1977 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve Frencheeac8042006-01-13 21:34:58 -08001978 cFYI(1,("file mode: 0x%x dir mode: 0x%x",
1979 cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Steve French4523cc32007-04-30 20:13:06 +00001981 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00001983 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00001985 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00001987 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07001988 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00001989 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00001991 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05001992 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00001993 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001994 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00001995 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08001996 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00001997 if (volume_info.override_uid)
1998 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
1999 if (volume_info.override_gid)
2000 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2001 if (volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002002 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2004 }
2005
2006 tcon =
2007 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2008 volume_info.username);
2009 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002010 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 /* we can have only one retry value for a connection
2012 to a share so for resources mounted more than once
2013 to the same server share the last value passed in
2014 for the retry flag is used */
2015 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002016 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 } else {
2018 tcon = tconInfoAlloc();
2019 if (tcon == NULL)
2020 rc = -ENOMEM;
2021 else {
Steve French8af18972007-02-14 04:42:51 +00002022 /* check for null share name ie connecting to
2023 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Steve French8af18972007-02-14 04:42:51 +00002025 /* BB check if this works for exactly length
2026 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2028 && (strchr(volume_info.UNC + 3, '/') ==
2029 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002030 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002031 "", cifs_sb->local_nls,
2032 cifs_sb->mnt_cifs_flags &
2033 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002034 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 FreeXid(xid);
2036 return -ENODEV;
2037 } else {
Steve French8af18972007-02-14 04:42:51 +00002038 /* BB Do we need to wrap sesSem around
2039 * this TCon call and Unix SetFS as
2040 * we do on SessSetup and reconnect? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 rc = CIFSTCon(xid, pSesInfo,
2042 volume_info.UNC,
2043 tcon, cifs_sb->local_nls);
2044 cFYI(1, ("CIFS Tcon rc = %d", rc));
2045 }
2046 if (!rc) {
2047 atomic_inc(&pSesInfo->inUse);
2048 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002049 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 }
2051 }
2052 }
2053 }
Steve French4523cc32007-04-30 20:13:06 +00002054 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2056 sb->s_maxbytes = (u64) 1 << 63;
2057 } else
2058 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2059 }
2060
Steve French8af18972007-02-14 04:42:51 +00002061 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 sb->s_time_gran = 100;
2063
2064/* on error free sesinfo and tcon struct if needed */
2065 if (rc) {
2066 /* if session setup failed, use count is zero but
2067 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002068 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 spin_lock(&GlobalMid_Lock);
2070 srvTcp->tcpStatus = CifsExiting;
2071 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002072 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002073 struct task_struct *tsk;
2074 /* If we could verify that kthread_stop would
2075 always wake up processes blocked in
2076 tcp in recv_mesg then we could remove the
2077 send_sig call */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 send_sig(SIGKILL,srvTcp->tsk,1);
Steve French28356a12007-05-23 14:45:36 +00002079 tsk = srvTcp->tsk;
2080 if(tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002081 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 }
2084 /* If find_unc succeeded then rc == 0 so we can not end */
2085 if (tcon) /* up accidently freeing someone elses tcon struct */
2086 tconInfoFree(tcon);
2087 if (existingCifsSes == NULL) {
2088 if (pSesInfo) {
2089 if ((pSesInfo->server) &&
2090 (pSesInfo->status == CifsGood)) {
2091 int temp_rc;
2092 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2093 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002094 if ((temp_rc == -ESHUTDOWN) &&
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002095 (pSesInfo->server) && (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002096 struct task_struct *tsk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve French28356a12007-05-23 14:45:36 +00002098 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002099 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002100 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 } else
2103 cFYI(1, ("No session or bad tcon"));
2104 sesInfoFree(pSesInfo);
2105 /* pSesInfo = NULL; */
2106 }
2107 }
2108 } else {
2109 atomic_inc(&tcon->useCount);
2110 cifs_sb->tcon = tcon;
2111 tcon->ses = pSesInfo;
2112
Steve French82940a42006-03-02 03:24:57 +00002113 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07002114 CIFSSMBQFSDeviceInfo(xid, tcon);
2115 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French8af18972007-02-14 04:42:51 +00002116
2117 /* tell server which Unix caps we support */
2118 if (tcon->ses->capabilities & CAP_UNIX)
2119 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
2120
Steve French3e844692005-10-03 13:37:24 -07002121 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2122 cifs_sb->wsize = min(cifs_sb->wsize,
2123 (tcon->ses->server->maxBuf -
2124 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002125 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2126 cifs_sb->rsize = min(cifs_sb->rsize,
2127 (tcon->ses->server->maxBuf -
2128 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 }
2130
2131 /* volume_info.password is freed above when existing session found
2132 (in which case it is not needed anymore) but when new sesion is created
2133 the password ptr is put in the new session structure (in which case the
2134 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002135 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002136 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 FreeXid(xid);
2138 return rc;
2139}
2140
2141static int
2142CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002143 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 const struct nls_table *nls_codepage)
2145{
2146 struct smb_hdr *smb_buffer;
2147 struct smb_hdr *smb_buffer_response;
2148 SESSION_SETUP_ANDX *pSMB;
2149 SESSION_SETUP_ANDX *pSMBr;
2150 char *bcc_ptr;
2151 char *user;
2152 char *domain;
2153 int rc = 0;
2154 int remaining_words = 0;
2155 int bytes_returned = 0;
2156 int len;
2157 __u32 capabilities;
2158 __u16 count;
2159
Steve Frencheeac8042006-01-13 21:34:58 -08002160 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002161 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 return -EINVAL;
2163 user = ses->userName;
2164 domain = ses->domainName;
2165 smb_buffer = cifs_buf_get();
2166 if (smb_buffer == NULL) {
2167 return -ENOMEM;
2168 }
2169 smb_buffer_response = smb_buffer;
2170 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2171
2172 /* send SMBsessionSetup here */
2173 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2174 NULL /* no tCon exists yet */ , 13 /* wct */ );
2175
Steve French1982c342005-08-17 12:38:22 -07002176 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 pSMB->req_no_secext.AndXCommand = 0xFF;
2178 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2179 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2180
2181 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2182 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2183
2184 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2185 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2186 if (ses->capabilities & CAP_UNICODE) {
2187 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2188 capabilities |= CAP_UNICODE;
2189 }
2190 if (ses->capabilities & CAP_STATUS32) {
2191 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2192 capabilities |= CAP_STATUS32;
2193 }
2194 if (ses->capabilities & CAP_DFS) {
2195 smb_buffer->Flags2 |= SMBFLG2_DFS;
2196 capabilities |= CAP_DFS;
2197 }
2198 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2199
2200 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002201 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
2203 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002204 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002206 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2207 bcc_ptr += CIFS_SESS_KEY_SIZE;
2208 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2209 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
2211 if (ses->capabilities & CAP_UNICODE) {
2212 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2213 *bcc_ptr = 0;
2214 bcc_ptr++;
2215 }
Steve French4523cc32007-04-30 20:13:06 +00002216 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002217 bytes_returned = 0; /* skip null user */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 else
2219 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002220 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 nls_codepage);
2222 /* convert number of 16 bit words to bytes */
2223 bcc_ptr += 2 * bytes_returned;
2224 bcc_ptr += 2; /* trailing null */
2225 if (domain == NULL)
2226 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002227 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 "CIFS_LINUX_DOM", 32, nls_codepage);
2229 else
2230 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002231 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 nls_codepage);
2233 bcc_ptr += 2 * bytes_returned;
2234 bcc_ptr += 2;
2235 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002236 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 32, nls_codepage);
2238 bcc_ptr += 2 * bytes_returned;
2239 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002240 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 32, nls_codepage);
2242 bcc_ptr += 2 * bytes_returned;
2243 bcc_ptr += 2;
2244 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002245 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 64, nls_codepage);
2247 bcc_ptr += 2 * bytes_returned;
2248 bcc_ptr += 2;
2249 } else {
Steve French4523cc32007-04-30 20:13:06 +00002250 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 strncpy(bcc_ptr, user, 200);
2252 bcc_ptr += strnlen(user, 200);
2253 }
2254 *bcc_ptr = 0;
2255 bcc_ptr++;
2256 if (domain == NULL) {
2257 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2258 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2259 } else {
2260 strncpy(bcc_ptr, domain, 64);
2261 bcc_ptr += strnlen(domain, 64);
2262 *bcc_ptr = 0;
2263 bcc_ptr++;
2264 }
2265 strcpy(bcc_ptr, "Linux version ");
2266 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002267 strcpy(bcc_ptr, utsname()->release);
2268 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2270 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2271 }
2272 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2273 smb_buffer->smb_buf_length += count;
2274 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2275
2276 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2277 &bytes_returned, 1);
2278 if (rc) {
2279/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2280 } else if ((smb_buffer_response->WordCount == 3)
2281 || (smb_buffer_response->WordCount == 4)) {
2282 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2283 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2284 if (action & GUEST_LOGIN)
2285 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2286 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2287 cFYI(1, ("UID = %d ", ses->Suid));
2288 /* response can have either 3 or 4 word count - Samba sends 3 */
2289 bcc_ptr = pByteArea(smb_buffer_response);
2290 if ((pSMBr->resp.hdr.WordCount == 3)
2291 || ((pSMBr->resp.hdr.WordCount == 4)
2292 && (blob_len < pSMBr->resp.ByteCount))) {
2293 if (pSMBr->resp.hdr.WordCount == 4)
2294 bcc_ptr += blob_len;
2295
2296 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2297 if ((long) (bcc_ptr) % 2) {
2298 remaining_words =
2299 (BCC(smb_buffer_response) - 1) /2;
2300 bcc_ptr++; /* Unicode strings must be word aligned */
2301 } else {
2302 remaining_words =
2303 BCC(smb_buffer_response) / 2;
2304 }
2305 len =
2306 UniStrnlen((wchar_t *) bcc_ptr,
2307 remaining_words - 1);
2308/* We look for obvious messed up bcc or strings in response so we do not go off
2309 the end since (at least) WIN2K and Windows XP have a major bug in not null
2310 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002311 if(ses->serverOS)
2312 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002313 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002314 if(ses->serverOS == NULL)
2315 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002317 (__le16 *)bcc_ptr, len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 bcc_ptr += 2 * (len + 1);
2319 remaining_words -= len + 1;
2320 ses->serverOS[2 * len] = 0;
2321 ses->serverOS[1 + (2 * len)] = 0;
2322 if (remaining_words > 0) {
2323 len = UniStrnlen((wchar_t *)bcc_ptr,
2324 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002325 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002326 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002327 if(ses->serverNOS == NULL)
2328 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002330 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 bcc_ptr += 2 * (len + 1);
2332 ses->serverNOS[2 * len] = 0;
2333 ses->serverNOS[1 + (2 * len)] = 0;
2334 if(strncmp(ses->serverNOS,
2335 "NT LAN Manager 4",16) == 0) {
2336 cFYI(1,("NT4 server"));
2337 ses->flags |= CIFS_SES_NT4;
2338 }
2339 remaining_words -= len + 1;
2340 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002341 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002343 if(ses->serverDomain)
2344 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002346 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002347 if(ses->serverDomain == NULL)
2348 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002350 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 bcc_ptr += 2 * (len + 1);
2352 ses->serverDomain[2*len] = 0;
2353 ses->serverDomain[1+(2*len)] = 0;
2354 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002355 else {
2356 if(ses->serverDomain)
2357 kfree(ses->serverDomain);
Steve French433dc242005-04-28 22:41:08 -07002358 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002359 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002362 /* if these kcallocs fail not much we
2363 can do, but better to not fail the
2364 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002365 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002367 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002368 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002370 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 }
2372 } else { /* ASCII */
2373 len = strnlen(bcc_ptr, 1024);
2374 if (((long) bcc_ptr + len) - (long)
2375 pByteArea(smb_buffer_response)
2376 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002377 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002378 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002379 if(ses->serverOS == NULL)
2380 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 strncpy(ses->serverOS,bcc_ptr, len);
2382
2383 bcc_ptr += len;
2384 bcc_ptr[0] = 0; /* null terminate the string */
2385 bcc_ptr++;
2386
2387 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002388 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002389 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002390 if(ses->serverNOS == NULL)
2391 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 strncpy(ses->serverNOS, bcc_ptr, len);
2393 bcc_ptr += len;
2394 bcc_ptr[0] = 0;
2395 bcc_ptr++;
2396
2397 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002398 if(ses->serverDomain)
2399 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002400 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002401 if(ses->serverDomain == NULL)
2402 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 strncpy(ses->serverDomain, bcc_ptr, len);
2404 bcc_ptr += len;
2405 bcc_ptr[0] = 0;
2406 bcc_ptr++;
2407 } else
2408 cFYI(1,
2409 ("Variable field of length %d extends beyond end of smb ",
2410 len));
2411 }
2412 } else {
2413 cERROR(1,
2414 (" Security Blob Length extends beyond end of SMB"));
2415 }
2416 } else {
2417 cERROR(1,
2418 (" Invalid Word count %d: ",
2419 smb_buffer_response->WordCount));
2420 rc = -EIO;
2421 }
Steve French433dc242005-04-28 22:41:08 -07002422sesssetup_nomem: /* do not return an error on nomem for the info strings,
2423 since that could make reconnection harder, and
2424 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 if (smb_buffer)
2426 cifs_buf_release(smb_buffer);
2427
2428 return rc;
2429}
2430
2431static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2433 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2434 const struct nls_table *nls_codepage)
2435{
2436 struct smb_hdr *smb_buffer;
2437 struct smb_hdr *smb_buffer_response;
2438 SESSION_SETUP_ANDX *pSMB;
2439 SESSION_SETUP_ANDX *pSMBr;
2440 char *bcc_ptr;
2441 char *domain;
2442 int rc = 0;
2443 int remaining_words = 0;
2444 int bytes_returned = 0;
2445 int len;
2446 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2447 PNEGOTIATE_MESSAGE SecurityBlob;
2448 PCHALLENGE_MESSAGE SecurityBlob2;
2449 __u32 negotiate_flags, capabilities;
2450 __u16 count;
2451
Steve French12b3b8f2006-02-09 21:12:47 +00002452 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 if(ses == NULL)
2454 return -EINVAL;
2455 domain = ses->domainName;
2456 *pNTLMv2_flag = FALSE;
2457 smb_buffer = cifs_buf_get();
2458 if (smb_buffer == NULL) {
2459 return -ENOMEM;
2460 }
2461 smb_buffer_response = smb_buffer;
2462 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2463 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2464
2465 /* send SMBsessionSetup here */
2466 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2467 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002468
2469 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2471 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2472
2473 pSMB->req.AndXCommand = 0xFF;
2474 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2475 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2476
2477 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2478 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2479
2480 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2481 CAP_EXTENDED_SECURITY;
2482 if (ses->capabilities & CAP_UNICODE) {
2483 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2484 capabilities |= CAP_UNICODE;
2485 }
2486 if (ses->capabilities & CAP_STATUS32) {
2487 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2488 capabilities |= CAP_STATUS32;
2489 }
2490 if (ses->capabilities & CAP_DFS) {
2491 smb_buffer->Flags2 |= SMBFLG2_DFS;
2492 capabilities |= CAP_DFS;
2493 }
2494 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2495
2496 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2497 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2498 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2499 SecurityBlob->MessageType = NtLmNegotiate;
2500 negotiate_flags =
2501 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002502 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2503 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2505 if(sign_CIFS_PDUs)
2506 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve French39798772006-05-31 22:40:51 +00002507/* if(ntlmv2_support)
2508 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 /* setup pointers to domain name and workstation name */
2510 bcc_ptr += SecurityBlobLength;
2511
2512 SecurityBlob->WorkstationName.Buffer = 0;
2513 SecurityBlob->WorkstationName.Length = 0;
2514 SecurityBlob->WorkstationName.MaximumLength = 0;
2515
Steve French12b3b8f2006-02-09 21:12:47 +00002516 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2517 along with username on auth request (ie the response to challenge) */
2518 SecurityBlob->DomainName.Buffer = 0;
2519 SecurityBlob->DomainName.Length = 0;
2520 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 if (ses->capabilities & CAP_UNICODE) {
2522 if ((long) bcc_ptr % 2) {
2523 *bcc_ptr = 0;
2524 bcc_ptr++;
2525 }
2526
2527 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002528 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 32, nls_codepage);
2530 bcc_ptr += 2 * bytes_returned;
2531 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002532 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 nls_codepage);
2534 bcc_ptr += 2 * bytes_returned;
2535 bcc_ptr += 2; /* null terminate Linux version */
2536 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002537 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 64, nls_codepage);
2539 bcc_ptr += 2 * bytes_returned;
2540 *(bcc_ptr + 1) = 0;
2541 *(bcc_ptr + 2) = 0;
2542 bcc_ptr += 2; /* null terminate network opsys string */
2543 *(bcc_ptr + 1) = 0;
2544 *(bcc_ptr + 2) = 0;
2545 bcc_ptr += 2; /* null domain */
2546 } else { /* ASCII */
2547 strcpy(bcc_ptr, "Linux version ");
2548 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002549 strcpy(bcc_ptr, utsname()->release);
2550 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2552 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2553 bcc_ptr++; /* empty domain field */
2554 *bcc_ptr = 0;
2555 }
2556 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2557 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2558 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2559 smb_buffer->smb_buf_length += count;
2560 pSMB->req.ByteCount = cpu_to_le16(count);
2561
2562 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2563 &bytes_returned, 1);
2564
2565 if (smb_buffer_response->Status.CifsError ==
2566 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2567 rc = 0;
2568
2569 if (rc) {
2570/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2571 } else if ((smb_buffer_response->WordCount == 3)
2572 || (smb_buffer_response->WordCount == 4)) {
2573 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2574 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2575
2576 if (action & GUEST_LOGIN)
2577 cFYI(1, (" Guest login"));
2578 /* Do we want to set anything in SesInfo struct when guest login? */
2579
2580 bcc_ptr = pByteArea(smb_buffer_response);
2581 /* response can have either 3 or 4 word count - Samba sends 3 */
2582
2583 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2584 if (SecurityBlob2->MessageType != NtLmChallenge) {
2585 cFYI(1,
2586 ("Unexpected NTLMSSP message type received %d",
2587 SecurityBlob2->MessageType));
2588 } else if (ses) {
2589 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002590 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 if ((pSMBr->resp.hdr.WordCount == 3)
2592 || ((pSMBr->resp.hdr.WordCount == 4)
2593 && (blob_len <
2594 pSMBr->resp.ByteCount))) {
2595
2596 if (pSMBr->resp.hdr.WordCount == 4) {
2597 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002598 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 blob_len));
2600 }
2601
Steve French12b3b8f2006-02-09 21:12:47 +00002602 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
2604 memcpy(ses->server->cryptKey,
2605 SecurityBlob2->Challenge,
2606 CIFS_CRYPTO_KEY_SIZE);
Steve French12b3b8f2006-02-09 21:12:47 +00002607 if(SecurityBlob2->NegotiateFlags &
2608 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 *pNTLMv2_flag = TRUE;
2610
2611 if((SecurityBlob2->NegotiateFlags &
2612 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2613 || (sign_CIFS_PDUs > 1))
2614 ses->server->secMode |=
2615 SECMODE_SIGN_REQUIRED;
2616 if ((SecurityBlob2->NegotiateFlags &
2617 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2618 ses->server->secMode |=
2619 SECMODE_SIGN_ENABLED;
2620
2621 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2622 if ((long) (bcc_ptr) % 2) {
2623 remaining_words =
2624 (BCC(smb_buffer_response)
2625 - 1) / 2;
2626 bcc_ptr++; /* Unicode strings must be word aligned */
2627 } else {
2628 remaining_words =
2629 BCC
2630 (smb_buffer_response) / 2;
2631 }
2632 len =
2633 UniStrnlen((wchar_t *) bcc_ptr,
2634 remaining_words - 1);
2635/* We look for obvious messed up bcc or strings in response so we do not go off
2636 the end since (at least) WIN2K and Windows XP have a major bug in not null
2637 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002638 if(ses->serverOS)
2639 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002641 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002643 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 bcc_ptr, len,
2645 nls_codepage);
2646 bcc_ptr += 2 * (len + 1);
2647 remaining_words -= len + 1;
2648 ses->serverOS[2 * len] = 0;
2649 ses->serverOS[1 + (2 * len)] = 0;
2650 if (remaining_words > 0) {
2651 len = UniStrnlen((wchar_t *)
2652 bcc_ptr,
2653 remaining_words
2654 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002655 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002657 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 GFP_KERNEL);
2659 cifs_strfromUCS_le(ses->
2660 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002661 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 bcc_ptr,
2663 len,
2664 nls_codepage);
2665 bcc_ptr += 2 * (len + 1);
2666 ses->serverNOS[2 * len] = 0;
2667 ses->serverNOS[1 +
2668 (2 * len)] = 0;
2669 remaining_words -= len + 1;
2670 if (remaining_words > 0) {
2671 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2672 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002673 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002675 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 (len +
2677 1),
2678 GFP_KERNEL);
2679 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002680 (ses->serverDomain,
2681 (__le16 *)bcc_ptr,
2682 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 bcc_ptr +=
2684 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002685 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002687 ses->serverDomain
2688 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 = 0;
2690 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002691 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002692 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002694 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002698 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002700 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002701 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002703 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 }
2705 } else { /* ASCII */
2706 len = strnlen(bcc_ptr, 1024);
2707 if (((long) bcc_ptr + len) - (long)
2708 pByteArea(smb_buffer_response)
2709 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002710 if(ses->serverOS)
2711 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002713 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 GFP_KERNEL);
2715 strncpy(ses->serverOS,
2716 bcc_ptr, len);
2717
2718 bcc_ptr += len;
2719 bcc_ptr[0] = 0; /* null terminate string */
2720 bcc_ptr++;
2721
2722 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002723 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002725 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 GFP_KERNEL);
2727 strncpy(ses->serverNOS, bcc_ptr, len);
2728 bcc_ptr += len;
2729 bcc_ptr[0] = 0;
2730 bcc_ptr++;
2731
2732 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002733 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002735 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 GFP_KERNEL);
2737 strncpy(ses->serverDomain, bcc_ptr, len);
2738 bcc_ptr += len;
2739 bcc_ptr[0] = 0;
2740 bcc_ptr++;
2741 } else
2742 cFYI(1,
Steve French12b3b8f2006-02-09 21:12:47 +00002743 ("Variable field of length %d extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 len));
2745 }
2746 } else {
2747 cERROR(1,
2748 (" Security Blob Length extends beyond end of SMB"));
2749 }
2750 } else {
2751 cERROR(1, ("No session structure passed in."));
2752 }
2753 } else {
2754 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002755 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 smb_buffer_response->WordCount));
2757 rc = -EIO;
2758 }
2759
2760 if (smb_buffer)
2761 cifs_buf_release(smb_buffer);
2762
2763 return rc;
2764}
2765static int
2766CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2767 char *ntlm_session_key, int ntlmv2_flag,
2768 const struct nls_table *nls_codepage)
2769{
2770 struct smb_hdr *smb_buffer;
2771 struct smb_hdr *smb_buffer_response;
2772 SESSION_SETUP_ANDX *pSMB;
2773 SESSION_SETUP_ANDX *pSMBr;
2774 char *bcc_ptr;
2775 char *user;
2776 char *domain;
2777 int rc = 0;
2778 int remaining_words = 0;
2779 int bytes_returned = 0;
2780 int len;
2781 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2782 PAUTHENTICATE_MESSAGE SecurityBlob;
2783 __u32 negotiate_flags, capabilities;
2784 __u16 count;
2785
2786 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2787 if(ses == NULL)
2788 return -EINVAL;
2789 user = ses->userName;
2790 domain = ses->domainName;
2791 smb_buffer = cifs_buf_get();
2792 if (smb_buffer == NULL) {
2793 return -ENOMEM;
2794 }
2795 smb_buffer_response = smb_buffer;
2796 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2797 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2798
2799 /* send SMBsessionSetup here */
2800 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2801 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002802
2803 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2805 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2806 pSMB->req.AndXCommand = 0xFF;
2807 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2808 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2809
2810 pSMB->req.hdr.Uid = ses->Suid;
2811
2812 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2813 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2814
2815 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2816 CAP_EXTENDED_SECURITY;
2817 if (ses->capabilities & CAP_UNICODE) {
2818 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2819 capabilities |= CAP_UNICODE;
2820 }
2821 if (ses->capabilities & CAP_STATUS32) {
2822 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2823 capabilities |= CAP_STATUS32;
2824 }
2825 if (ses->capabilities & CAP_DFS) {
2826 smb_buffer->Flags2 |= SMBFLG2_DFS;
2827 capabilities |= CAP_DFS;
2828 }
2829 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2830
2831 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2832 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2833 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2834 SecurityBlob->MessageType = NtLmAuthenticate;
2835 bcc_ptr += SecurityBlobLength;
2836 negotiate_flags =
2837 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2838 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2839 0x80000000 | NTLMSSP_NEGOTIATE_128;
2840 if(sign_CIFS_PDUs)
2841 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2842 if(ntlmv2_flag)
2843 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2844
2845/* setup pointers to domain name and workstation name */
2846
2847 SecurityBlob->WorkstationName.Buffer = 0;
2848 SecurityBlob->WorkstationName.Length = 0;
2849 SecurityBlob->WorkstationName.MaximumLength = 0;
2850 SecurityBlob->SessionKey.Length = 0;
2851 SecurityBlob->SessionKey.MaximumLength = 0;
2852 SecurityBlob->SessionKey.Buffer = 0;
2853
2854 SecurityBlob->LmChallengeResponse.Length = 0;
2855 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2856 SecurityBlob->LmChallengeResponse.Buffer = 0;
2857
2858 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002859 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002861 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2862 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 SecurityBlob->NtChallengeResponse.Buffer =
2864 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002865 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2866 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867
2868 if (ses->capabilities & CAP_UNICODE) {
2869 if (domain == NULL) {
2870 SecurityBlob->DomainName.Buffer = 0;
2871 SecurityBlob->DomainName.Length = 0;
2872 SecurityBlob->DomainName.MaximumLength = 0;
2873 } else {
2874 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002875 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 nls_codepage);
2877 len *= 2;
2878 SecurityBlob->DomainName.MaximumLength =
2879 cpu_to_le16(len);
2880 SecurityBlob->DomainName.Buffer =
2881 cpu_to_le32(SecurityBlobLength);
2882 bcc_ptr += len;
2883 SecurityBlobLength += len;
2884 SecurityBlob->DomainName.Length =
2885 cpu_to_le16(len);
2886 }
2887 if (user == NULL) {
2888 SecurityBlob->UserName.Buffer = 0;
2889 SecurityBlob->UserName.Length = 0;
2890 SecurityBlob->UserName.MaximumLength = 0;
2891 } else {
2892 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002893 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 nls_codepage);
2895 len *= 2;
2896 SecurityBlob->UserName.MaximumLength =
2897 cpu_to_le16(len);
2898 SecurityBlob->UserName.Buffer =
2899 cpu_to_le32(SecurityBlobLength);
2900 bcc_ptr += len;
2901 SecurityBlobLength += len;
2902 SecurityBlob->UserName.Length =
2903 cpu_to_le16(len);
2904 }
2905
Steve Frenche89dc922005-11-11 15:18:19 -08002906 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 SecurityBlob->WorkstationName.Length *= 2;
2908 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2909 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2910 bcc_ptr += SecurityBlob->WorkstationName.Length;
2911 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2912 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2913
2914 if ((long) bcc_ptr % 2) {
2915 *bcc_ptr = 0;
2916 bcc_ptr++;
2917 }
2918 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002919 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 32, nls_codepage);
2921 bcc_ptr += 2 * bytes_returned;
2922 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002923 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 nls_codepage);
2925 bcc_ptr += 2 * bytes_returned;
2926 bcc_ptr += 2; /* null term version string */
2927 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002928 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 64, nls_codepage);
2930 bcc_ptr += 2 * bytes_returned;
2931 *(bcc_ptr + 1) = 0;
2932 *(bcc_ptr + 2) = 0;
2933 bcc_ptr += 2; /* null terminate network opsys string */
2934 *(bcc_ptr + 1) = 0;
2935 *(bcc_ptr + 2) = 0;
2936 bcc_ptr += 2; /* null domain */
2937 } else { /* ASCII */
2938 if (domain == NULL) {
2939 SecurityBlob->DomainName.Buffer = 0;
2940 SecurityBlob->DomainName.Length = 0;
2941 SecurityBlob->DomainName.MaximumLength = 0;
2942 } else {
2943 __u16 len;
2944 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2945 strncpy(bcc_ptr, domain, 63);
2946 len = strnlen(domain, 64);
2947 SecurityBlob->DomainName.MaximumLength =
2948 cpu_to_le16(len);
2949 SecurityBlob->DomainName.Buffer =
2950 cpu_to_le32(SecurityBlobLength);
2951 bcc_ptr += len;
2952 SecurityBlobLength += len;
2953 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2954 }
2955 if (user == NULL) {
2956 SecurityBlob->UserName.Buffer = 0;
2957 SecurityBlob->UserName.Length = 0;
2958 SecurityBlob->UserName.MaximumLength = 0;
2959 } else {
2960 __u16 len;
2961 strncpy(bcc_ptr, user, 63);
2962 len = strnlen(user, 64);
2963 SecurityBlob->UserName.MaximumLength =
2964 cpu_to_le16(len);
2965 SecurityBlob->UserName.Buffer =
2966 cpu_to_le32(SecurityBlobLength);
2967 bcc_ptr += len;
2968 SecurityBlobLength += len;
2969 SecurityBlob->UserName.Length = cpu_to_le16(len);
2970 }
2971 /* BB fill in our workstation name if known BB */
2972
2973 strcpy(bcc_ptr, "Linux version ");
2974 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002975 strcpy(bcc_ptr, utsname()->release);
2976 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2978 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2979 bcc_ptr++; /* null domain */
2980 *bcc_ptr = 0;
2981 }
2982 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2983 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2984 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2985 smb_buffer->smb_buf_length += count;
2986 pSMB->req.ByteCount = cpu_to_le16(count);
2987
2988 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2989 &bytes_returned, 1);
2990 if (rc) {
2991/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2992 } else if ((smb_buffer_response->WordCount == 3)
2993 || (smb_buffer_response->WordCount == 4)) {
2994 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2995 __u16 blob_len =
2996 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2997 if (action & GUEST_LOGIN)
2998 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2999/* if(SecurityBlob2->MessageType != NtLm??){
3000 cFYI("Unexpected message type on auth response is %d "));
3001 } */
3002 if (ses) {
3003 cFYI(1,
3004 ("Does UID on challenge %d match auth response UID %d ",
3005 ses->Suid, smb_buffer_response->Uid));
3006 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3007 bcc_ptr = pByteArea(smb_buffer_response);
3008 /* response can have either 3 or 4 word count - Samba sends 3 */
3009 if ((pSMBr->resp.hdr.WordCount == 3)
3010 || ((pSMBr->resp.hdr.WordCount == 4)
3011 && (blob_len <
3012 pSMBr->resp.ByteCount))) {
3013 if (pSMBr->resp.hdr.WordCount == 4) {
3014 bcc_ptr +=
3015 blob_len;
3016 cFYI(1,
3017 ("Security Blob Length %d ",
3018 blob_len));
3019 }
3020
3021 cFYI(1,
3022 ("NTLMSSP response to Authenticate "));
3023
3024 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3025 if ((long) (bcc_ptr) % 2) {
3026 remaining_words =
3027 (BCC(smb_buffer_response)
3028 - 1) / 2;
3029 bcc_ptr++; /* Unicode strings must be word aligned */
3030 } else {
3031 remaining_words = BCC(smb_buffer_response) / 2;
3032 }
3033 len =
3034 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3035/* We look for obvious messed up bcc or strings in response so we do not go off
3036 the end since (at least) WIN2K and Windows XP have a major bug in not null
3037 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00003038 if(ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003039 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003041 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003043 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 bcc_ptr, len,
3045 nls_codepage);
3046 bcc_ptr += 2 * (len + 1);
3047 remaining_words -= len + 1;
3048 ses->serverOS[2 * len] = 0;
3049 ses->serverOS[1 + (2 * len)] = 0;
3050 if (remaining_words > 0) {
3051 len = UniStrnlen((wchar_t *)
3052 bcc_ptr,
3053 remaining_words
3054 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003055 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003057 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 GFP_KERNEL);
3059 cifs_strfromUCS_le(ses->
3060 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003061 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 bcc_ptr,
3063 len,
3064 nls_codepage);
3065 bcc_ptr += 2 * (len + 1);
3066 ses->serverNOS[2 * len] = 0;
3067 ses->serverNOS[1+(2*len)] = 0;
3068 remaining_words -= len + 1;
3069 if (remaining_words > 0) {
3070 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3071 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00003072 if(ses->serverDomain)
3073 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003075 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 (len +
3077 1),
3078 GFP_KERNEL);
3079 cifs_strfromUCS_le
3080 (ses->
3081 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003082 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 bcc_ptr, len,
3084 nls_codepage);
3085 bcc_ptr +=
3086 2 * (len + 1);
3087 ses->
3088 serverDomain[2
3089 * len]
3090 = 0;
3091 ses->
3092 serverDomain[1
3093 +
3094 (2
3095 *
3096 len)]
3097 = 0;
3098 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003099 else {
3100 if(ses->serverDomain)
3101 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003102 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 } else { /* no room so create dummy domain and NOS string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003105 if(ses->serverDomain)
3106 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003107 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003108 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003109 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 }
3111 } else { /* ASCII */
3112 len = strnlen(bcc_ptr, 1024);
3113 if (((long) bcc_ptr + len) -
3114 (long) pByteArea(smb_buffer_response)
3115 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00003116 if(ses->serverOS)
3117 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003118 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 strncpy(ses->serverOS,bcc_ptr, len);
3120
3121 bcc_ptr += len;
3122 bcc_ptr[0] = 0; /* null terminate the string */
3123 bcc_ptr++;
3124
3125 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003126 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003127 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 strncpy(ses->serverNOS, bcc_ptr, len);
3129 bcc_ptr += len;
3130 bcc_ptr[0] = 0;
3131 bcc_ptr++;
3132
3133 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00003134 if(ses->serverDomain)
3135 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003136 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 strncpy(ses->serverDomain, bcc_ptr, len);
3138 bcc_ptr += len;
3139 bcc_ptr[0] = 0;
3140 bcc_ptr++;
3141 } else
3142 cFYI(1,
3143 ("Variable field of length %d extends beyond end of smb ",
3144 len));
3145 }
3146 } else {
3147 cERROR(1,
3148 (" Security Blob Length extends beyond end of SMB"));
3149 }
3150 } else {
3151 cERROR(1, ("No session structure passed in."));
3152 }
3153 } else {
3154 cERROR(1,
3155 (" Invalid Word count %d: ",
3156 smb_buffer_response->WordCount));
3157 rc = -EIO;
3158 }
3159
3160 if (smb_buffer)
3161 cifs_buf_release(smb_buffer);
3162
3163 return rc;
3164}
3165
3166int
3167CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3168 const char *tree, struct cifsTconInfo *tcon,
3169 const struct nls_table *nls_codepage)
3170{
3171 struct smb_hdr *smb_buffer;
3172 struct smb_hdr *smb_buffer_response;
3173 TCONX_REQ *pSMB;
3174 TCONX_RSP *pSMBr;
3175 unsigned char *bcc_ptr;
3176 int rc = 0;
3177 int length;
3178 __u16 count;
3179
3180 if (ses == NULL)
3181 return -EIO;
3182
3183 smb_buffer = cifs_buf_get();
3184 if (smb_buffer == NULL) {
3185 return -ENOMEM;
3186 }
3187 smb_buffer_response = smb_buffer;
3188
3189 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3190 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003191
3192 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 smb_buffer->Uid = ses->Suid;
3194 pSMB = (TCONX_REQ *) smb_buffer;
3195 pSMBr = (TCONX_RSP *) smb_buffer_response;
3196
3197 pSMB->AndXCommand = 0xFF;
3198 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 bcc_ptr = &pSMB->Password[0];
Steve Frencheeac8042006-01-13 21:34:58 -08003200 if((ses->server->secMode) & SECMODE_USER) {
3201 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003202 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003203 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003204 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003205 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003206 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003207 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3208 specified as required (when that support is added to
3209 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003210 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003211 by Samba (not sure whether other servers allow
3212 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003213#ifdef CONFIG_CIFS_WEAK_PW_HASH
3214 if((extended_security & CIFSSEC_MAY_LANMAN) &&
3215 (ses->server->secType == LANMAN))
3216 calc_lanman_hash(ses, bcc_ptr);
3217 else
3218#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003219 SMBNTencrypt(ses->password,
3220 ses->server->cryptKey,
3221 bcc_ptr);
3222
Steve French7c7b25b2006-06-01 19:20:10 +00003223 bcc_ptr += CIFS_SESS_KEY_SIZE;
3224 if(ses->capabilities & CAP_UNICODE) {
3225 /* must align unicode strings */
3226 *bcc_ptr = 0; /* null byte password */
3227 bcc_ptr++;
3228 }
Steve Frencheeac8042006-01-13 21:34:58 -08003229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230
Steve Frencha878fb22006-05-30 18:04:19 +00003231 if(ses->server->secMode &
3232 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3234
3235 if (ses->capabilities & CAP_STATUS32) {
3236 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3237 }
3238 if (ses->capabilities & CAP_DFS) {
3239 smb_buffer->Flags2 |= SMBFLG2_DFS;
3240 }
3241 if (ses->capabilities & CAP_UNICODE) {
3242 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3243 length =
Steve Frencha878fb22006-05-30 18:04:19 +00003244 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3245 6 /* max utf8 char length in bytes */ *
3246 (/* server len*/ + 256 /* share len */), nls_codepage);
3247 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 bcc_ptr += 2; /* skip trailing null */
3249 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 strcpy(bcc_ptr, tree);
3251 bcc_ptr += strlen(tree) + 1;
3252 }
3253 strcpy(bcc_ptr, "?????");
3254 bcc_ptr += strlen("?????");
3255 bcc_ptr += 1;
3256 count = bcc_ptr - &pSMB->Password[0];
3257 pSMB->hdr.smb_buf_length += count;
3258 pSMB->ByteCount = cpu_to_le16(count);
3259
3260 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3261
3262 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3263 /* above now done in SendReceive */
3264 if ((rc == 0) && (tcon != NULL)) {
3265 tcon->tidStatus = CifsGood;
3266 tcon->tid = smb_buffer_response->Tid;
3267 bcc_ptr = pByteArea(smb_buffer_response);
3268 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3269 /* skip service field (NB: this field is always ASCII) */
3270 bcc_ptr += length + 1;
3271 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3272 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3273 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3274 if ((bcc_ptr + (2 * length)) -
3275 pByteArea(smb_buffer_response) <=
3276 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003277 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003279 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003281 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 length, nls_codepage);
3283 bcc_ptr += 2 * length;
3284 bcc_ptr[0] = 0; /* null terminate the string */
3285 bcc_ptr[1] = 0;
3286 bcc_ptr += 2;
3287 }
3288 /* else do not bother copying these informational fields */
3289 } else {
3290 length = strnlen(bcc_ptr, 1024);
3291 if ((bcc_ptr + length) -
3292 pByteArea(smb_buffer_response) <=
3293 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003294 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003296 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 strncpy(tcon->nativeFileSystem, bcc_ptr,
3298 length);
3299 }
3300 /* else do not bother copying these informational fields */
3301 }
Steve French1a4e15a2006-10-12 21:33:51 +00003302 if((smb_buffer_response->WordCount == 3) ||
3303 (smb_buffer_response->WordCount == 7))
3304 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003305 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3306 else
3307 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3309 } else if ((rc == 0) && tcon == NULL) {
3310 /* all we need to save for IPC$ connection */
3311 ses->ipc_tid = smb_buffer_response->Tid;
3312 }
3313
3314 if (smb_buffer)
3315 cifs_buf_release(smb_buffer);
3316 return rc;
3317}
3318
3319int
3320cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3321{
3322 int rc = 0;
3323 int xid;
3324 struct cifsSesInfo *ses = NULL;
3325 struct task_struct *cifsd_task;
Steve French2fe87f02006-09-21 07:02:52 +00003326 char * tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327
3328 xid = GetXid();
3329
3330 if (cifs_sb->tcon) {
3331 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3332 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3333 if (rc == -EBUSY) {
3334 FreeXid(xid);
3335 return 0;
3336 }
3337 tconInfoFree(cifs_sb->tcon);
3338 if ((ses) && (ses->server)) {
3339 /* save off task so we do not refer to ses later */
3340 cifsd_task = ses->server->tsk;
3341 cFYI(1, ("About to do SMBLogoff "));
3342 rc = CIFSSMBLogoff(xid, ses);
3343 if (rc == -EBUSY) {
3344 FreeXid(xid);
3345 return 0;
3346 } else if (rc == -ESHUTDOWN) {
3347 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003348 if (cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 send_sig(SIGKILL,cifsd_task,1);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003350 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 rc = 0;
3353 } /* else - we have an smb session
3354 left on this socket do not kill cifsd */
3355 } else
3356 cFYI(1, ("No session or bad tcon"));
3357 }
3358
3359 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003360 tmp = cifs_sb->prepath;
3361 cifs_sb->prepathlen = 0;
3362 cifs_sb->prepath = NULL;
3363 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003364 if (ses)
3365 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 if (ses)
3367 sesInfoFree(ses);
3368
3369 FreeXid(xid);
3370 return rc; /* BB check if we should always return zero here */
3371}
3372
3373int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3374 struct nls_table * nls_info)
3375{
3376 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003377 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003379 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380
3381 /* what if server changes its buffer size after dropping the session? */
3382 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3383 rc = CIFSSMBNegotiate(xid, pSesInfo);
3384 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3385 rc = CIFSSMBNegotiate(xid, pSesInfo);
3386 if(rc == -EAGAIN)
3387 rc = -EHOSTDOWN;
3388 }
3389 if(rc == 0) {
3390 spin_lock(&GlobalMid_Lock);
3391 if(pSesInfo->server->tcpStatus != CifsExiting)
3392 pSesInfo->server->tcpStatus = CifsGood;
3393 else
3394 rc = -EHOSTDOWN;
3395 spin_unlock(&GlobalMid_Lock);
3396
3397 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003398 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 }
3400 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003401 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 pSesInfo->capabilities = pSesInfo->server->capabilities;
3403 if(linuxExtEnabled == 0)
3404 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003405 /* pSesInfo->sequence_number = 0;*/
Steve French175ec9e2006-09-30 01:07:38 +00003406 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 pSesInfo->server->secMode,
3408 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003409 pSesInfo->server->timeAdj));
Steve French189acaa2006-06-23 02:33:48 +00003410 if(experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003411 rc = CIFS_SessSetup(xid, pSesInfo,
3412 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003413 else if (extended_security
Steve French175ec9e2006-09-30 01:07:38 +00003414 && (pSesInfo->capabilities
3415 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003417 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 } else if (extended_security
3419 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3420 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003421 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3423 pSesInfo,
3424 &ntlmv2_flag,
3425 nls_info);
3426 if (!rc) {
3427 if(ntlmv2_flag) {
3428 char * v2_response;
Steve French175ec9e2006-09-30 01:07:38 +00003429 cFYI(1,("more secure NTLM ver2 hash"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3431 nls_info)) {
3432 rc = -ENOMEM;
3433 goto ss_err_exit;
3434 } else
3435 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3436 if(v2_response) {
3437 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003438 /* if(first_time)
3439 cifs_calculate_ntlmv2_mac_key(
3440 pSesInfo->server->mac_signing_key,
3441 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 kfree(v2_response);
3443 /* BB Put dummy sig in SessSetup PDU? */
3444 } else {
3445 rc = -ENOMEM;
3446 goto ss_err_exit;
3447 }
3448
3449 } else {
3450 SMBNTencrypt(pSesInfo->password,
3451 pSesInfo->server->cryptKey,
3452 ntlm_session_key);
3453
Steve Frenchad009ac2005-04-28 22:41:05 -07003454 if(first_time)
3455 cifs_calculate_mac_key(
3456 pSesInfo->server->mac_signing_key,
3457 ntlm_session_key,
3458 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 }
3460 /* for better security the weaker lanman hash not sent
3461 in AuthSessSetup so we no longer calculate it */
3462
3463 rc = CIFSNTLMSSPAuthSessSetup(xid,
3464 pSesInfo,
3465 ntlm_session_key,
3466 ntlmv2_flag,
3467 nls_info);
3468 }
3469 } else { /* old style NTLM 0.12 session setup */
3470 SMBNTencrypt(pSesInfo->password,
3471 pSesInfo->server->cryptKey,
3472 ntlm_session_key);
3473
Steve Frenchad009ac2005-04-28 22:41:05 -07003474 if(first_time)
3475 cifs_calculate_mac_key(
3476 pSesInfo->server->mac_signing_key,
3477 ntlm_session_key, pSesInfo->password);
3478
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 rc = CIFSSessSetup(xid, pSesInfo,
3480 ntlm_session_key, nls_info);
3481 }
3482 if (rc) {
3483 cERROR(1,("Send error in SessSetup = %d",rc));
3484 } else {
3485 cFYI(1,("CIFS Session Established successfully"));
3486 pSesInfo->status = CifsGood;
3487 }
3488 }
3489ss_err_exit:
3490 return rc;
3491}
3492