blob: a8f0cbada0f0ac23dfa4e40126ba72de0147b795 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve Frenchb8643e12005-04-28 22:41:07 -07004 * Copyright (C) International Business Machines Corp., 2002,2005
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>
Steve French0ae0efa2005-10-10 10:57:19 -070033#include <linux/pagevec.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/uaccess.h>
35#include <asm/processor.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
38#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41#include "cifs_fs_sb.h"
42#include "ntlmssp.h"
43#include "nterr.h"
44#include "rfc1002pdu.h"
45
46#define CIFS_PORT 445
47#define RFC1001_PORT 139
48
Steve Frenchf1914012005-08-18 09:37:34 -070049static DECLARE_COMPLETION(cifsd_complete);
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
52 unsigned char *p24);
53extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
54 unsigned char *p24);
55
56extern mempool_t *cifs_req_poolp;
57
58struct smb_vol {
59 char *username;
60 char *password;
61 char *domainname;
62 char *UNC;
63 char *UNCip;
64 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
65 char *iocharset; /* local code page for mapping to and from Unicode */
66 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070067 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 uid_t linux_uid;
69 gid_t linux_gid;
70 mode_t file_mode;
71 mode_t dir_mode;
72 unsigned rw:1;
73 unsigned retry:1;
74 unsigned intr:1;
75 unsigned setuids:1;
76 unsigned noperm:1;
77 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
78 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
79 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
80 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070081 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Jeremy Allisonac670552005-06-22 17:26:35 -070082 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
Steve Frenchd7245c22005-07-14 18:25:12 -050083 unsigned sfu_emul:1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -070084 unsigned nocase; /* request case insensitive filenames */
85 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 unsigned int rsize;
87 unsigned int wsize;
88 unsigned int sockopt;
89 unsigned short int port;
90};
91
92static int ipv4_connect(struct sockaddr_in *psin_server,
93 struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -070094 char * netb_name,
95 char * server_netb_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096static int ipv6_connect(struct sockaddr_in6 *psin_server,
97 struct socket **csocket);
98
99
100 /*
101 * cifs tcp session reconnection
102 *
103 * mark tcp session as reconnecting so temporarily locked
104 * mark all smb sessions as reconnecting for tcp session
105 * reconnect tcp session
106 * wake up waiters on reconnection? - (not needed currently)
107 */
108
109int
110cifs_reconnect(struct TCP_Server_Info *server)
111{
112 int rc = 0;
113 struct list_head *tmp;
114 struct cifsSesInfo *ses;
115 struct cifsTconInfo *tcon;
116 struct mid_q_entry * mid_entry;
117
118 spin_lock(&GlobalMid_Lock);
119 if(server->tcpStatus == CifsExiting) {
120 /* the demux thread will exit normally
121 next time through the loop */
122 spin_unlock(&GlobalMid_Lock);
123 return rc;
124 } else
125 server->tcpStatus = CifsNeedReconnect;
126 spin_unlock(&GlobalMid_Lock);
127 server->maxBuf = 0;
128
Steve Frenche4eb2952005-04-28 22:41:09 -0700129 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131 /* before reconnecting the tcp session, mark the smb session (uid)
132 and the tid bad so they are not used until reconnected */
133 read_lock(&GlobalSMBSeslock);
134 list_for_each(tmp, &GlobalSMBSessionList) {
135 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
136 if (ses->server) {
137 if (ses->server == server) {
138 ses->status = CifsNeedReconnect;
139 ses->ipc_tid = 0;
140 }
141 }
142 /* else tcp and smb sessions need reconnection */
143 }
144 list_for_each(tmp, &GlobalTreeConnectionList) {
145 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
146 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
147 tcon->tidStatus = CifsNeedReconnect;
148 }
149 }
150 read_unlock(&GlobalSMBSeslock);
151 /* do not want to be sending data on a socket we are freeing */
152 down(&server->tcpSem);
153 if(server->ssocket) {
154 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
155 server->ssocket->flags));
156 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
157 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
158 server->ssocket->flags));
159 sock_release(server->ssocket);
160 server->ssocket = NULL;
161 }
162
163 spin_lock(&GlobalMid_Lock);
164 list_for_each(tmp, &server->pending_mid_q) {
165 mid_entry = list_entry(tmp, struct
166 mid_q_entry,
167 qhead);
168 if(mid_entry) {
169 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700170 /* Mark other intransit requests as needing
171 retry so we do not immediately mark the
172 session bad again (ie after we reconnect
173 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 mid_entry->midState = MID_RETRY_NEEDED;
175 }
176 }
177 }
178 spin_unlock(&GlobalMid_Lock);
179 up(&server->tcpSem);
180
181 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
182 {
183 if(server->protocolType == IPV6) {
184 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
185 } else {
186 rc = ipv4_connect(&server->addr.sockAddr,
187 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700188 server->workstation_RFC1001_name,
189 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 }
191 if(rc) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700192 cFYI(1,("reconnect error %d",rc));
Steve French0cb766a2005-04-28 22:41:11 -0700193 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 } else {
195 atomic_inc(&tcpSesReconnectCount);
196 spin_lock(&GlobalMid_Lock);
197 if(server->tcpStatus != CifsExiting)
198 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700199 server->sequence_number = 0;
200 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 /* atomic_set(&server->inFlight,0);*/
202 wake_up(&server->response_q);
203 }
204 }
205 return rc;
206}
207
Steve Frenche4eb2952005-04-28 22:41:09 -0700208/*
209 return codes:
210 0 not a transact2, or all data present
211 >0 transact2 with that much data missing
212 -EINVAL = invalid transact2
213
214 */
215static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
216{
217 struct smb_t2_rsp * pSMBt;
218 int total_data_size;
219 int data_in_this_rsp;
220 int remaining;
221
222 if(pSMB->Command != SMB_COM_TRANSACTION2)
223 return 0;
224
225 /* check for plausible wct, bcc and t2 data and parm sizes */
226 /* check for parm and data offset going beyond end of smb */
227 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
228 cFYI(1,("invalid transact2 word count"));
229 return -EINVAL;
230 }
231
232 pSMBt = (struct smb_t2_rsp *)pSMB;
233
234 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
235 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
236
237 remaining = total_data_size - data_in_this_rsp;
238
239 if(remaining == 0)
240 return 0;
241 else if(remaining < 0) {
242 cFYI(1,("total data %d smaller than data in frame %d",
243 total_data_size, data_in_this_rsp));
244 return -EINVAL;
245 } else {
246 cFYI(1,("missing %d bytes from transact2, check next response",
247 remaining));
248 if(total_data_size > maxBufSize) {
249 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
250 total_data_size,maxBufSize));
251 return -EINVAL;
252 }
253 return remaining;
254 }
255}
256
257static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
258{
259 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
260 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
261 int total_data_size;
262 int total_in_buf;
263 int remaining;
264 int total_in_buf2;
265 char * data_area_of_target;
266 char * data_area_of_buf2;
267 __u16 byte_count;
268
269 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
270
271 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
272 cFYI(1,("total data sizes of primary and secondary t2 differ"));
273 }
274
275 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
276
277 remaining = total_data_size - total_in_buf;
278
279 if(remaining < 0)
280 return -EINVAL;
281
282 if(remaining == 0) /* nothing to do, ignore */
283 return 0;
284
285 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
286 if(remaining < total_in_buf2) {
287 cFYI(1,("transact2 2nd response contains too much data"));
288 }
289
290 /* find end of first SMB data area */
291 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
292 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
293 /* validate target area */
294
295 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
296 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
297
298 data_area_of_target += total_in_buf;
299
300 /* copy second buffer into end of first buffer */
301 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
302 total_in_buf += total_in_buf2;
303 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
304 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
305 byte_count += total_in_buf2;
306 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
307
Steve French70ca7342005-09-22 16:32:06 -0700308 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700309 byte_count += total_in_buf2;
310
311 /* BB also add check that we are not beyond maximum buffer size */
312
Steve French70ca7342005-09-22 16:32:06 -0700313 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700314
315 if(remaining == total_in_buf2) {
316 cFYI(1,("found the last secondary response"));
317 return 0; /* we are done */
318 } else /* more responses to go */
319 return 1;
320
321}
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323static int
324cifs_demultiplex_thread(struct TCP_Server_Info *server)
325{
326 int length;
327 unsigned int pdu_length, total_read;
328 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700329 struct smb_hdr *bigbuf = NULL;
330 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 struct msghdr smb_msg;
332 struct kvec iov;
333 struct socket *csocket = server->ssocket;
334 struct list_head *tmp;
335 struct cifsSesInfo *ses;
336 struct task_struct *task_to_wake = NULL;
337 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700338 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700339 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700340 int isMultiRsp;
341 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 daemonize("cifsd");
344 allow_signal(SIGKILL);
345 current->flags |= PF_MEMALLOC;
346 server->tsk = current; /* save process info to wake at shutdown */
347 cFYI(1, ("Demultiplex PID: %d", current->pid));
348 write_lock(&GlobalSMBSeslock);
349 atomic_inc(&tcpSesAllocCount);
350 length = tcpSesAllocCount.counter;
351 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700352 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if(length > 1) {
354 mempool_resize(cifs_req_poolp,
355 length + cifs_min_rcv,
356 GFP_KERNEL);
357 }
358
359 while (server->tcpStatus != CifsExiting) {
Steve French16abbec2005-08-30 13:10:14 -0700360 if(try_to_freeze())
361 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700362 if (bigbuf == NULL) {
363 bigbuf = cifs_buf_get();
364 if(bigbuf == NULL) {
365 cERROR(1,("No memory for large SMB response"));
366 msleep(3000);
367 /* retry will check if exiting */
368 continue;
369 }
370 } else if(isLargeBuf) {
371 /* we are reusing a dirtry large buf, clear its start */
372 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700374
375 if (smallbuf == NULL) {
376 smallbuf = cifs_small_buf_get();
377 if(smallbuf == NULL) {
378 cERROR(1,("No memory for SMB response"));
379 msleep(1000);
380 /* retry will check if exiting */
381 continue;
382 }
383 /* beginning of smb buffer is cleared in our buf_get */
384 } else /* if existing small buf clear beginning */
385 memset(smallbuf, 0, sizeof (struct smb_hdr));
386
387 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700388 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700389 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 iov.iov_base = smb_buffer;
391 iov.iov_len = 4;
392 smb_msg.msg_control = NULL;
393 smb_msg.msg_controllen = 0;
394 length =
395 kernel_recvmsg(csocket, &smb_msg,
396 &iov, 1, 4, 0 /* BB see socket.h flags */);
397
398 if(server->tcpStatus == CifsExiting) {
399 break;
400 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French57337e42005-04-28 22:41:10 -0700401 cFYI(1,("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 cifs_reconnect(server);
403 cFYI(1,("call to reconnect done"));
404 csocket = server->ssocket;
405 continue;
406 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700407 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 allowing socket to clear and app threads to set
409 tcpStatus CifsNeedReconnect if server hung */
410 continue;
411 } else if (length <= 0) {
412 if(server->tcpStatus == CifsNew) {
Steve French57337e42005-04-28 22:41:10 -0700413 cFYI(1,("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700414 /* some servers kill the TCP session rather than
415 returning an SMB negprot error, in which
416 case reconnecting here is not going to help,
417 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 break;
419 }
420 if(length == -EINTR) {
421 cFYI(1,("cifsd thread killed"));
422 break;
423 }
Steve French57337e42005-04-28 22:41:10 -0700424 cFYI(1,("Reconnect after unexpected peek error %d",
425 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 cifs_reconnect(server);
427 csocket = server->ssocket;
428 wake_up(&server->response_q);
429 continue;
Steve French46810cb2005-04-28 22:41:09 -0700430 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700432 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 length));
434 cifs_reconnect(server);
435 csocket = server->ssocket;
436 wake_up(&server->response_q);
437 continue;
438 }
Steve French67010fb2005-04-28 22:41:09 -0700439
Steve French70ca7342005-09-22 16:32:06 -0700440 /* The right amount was read from socket - 4 bytes */
441 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700442
Steve French70ca7342005-09-22 16:32:06 -0700443 /* the first byte big endian of the length field,
444 is actually not part of the length but the type
445 with the most common, zero, as regular data */
446 temp = *((char *) smb_buffer);
447
448 /* Note that FC 1001 length is big endian on the wire,
449 but we convert it here so it is always manipulated
450 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700451 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700452 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700453
Steve French70ca7342005-09-22 16:32:06 -0700454 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
455
456 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700457 continue;
Steve French70ca7342005-09-22 16:32:06 -0700458 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700459 cFYI(1,("Good RFC 1002 session rsp"));
460 continue;
Steve French70ca7342005-09-22 16:32:06 -0700461 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve French46810cb2005-04-28 22:41:09 -0700462 /* we get this from Windows 98 instead of
463 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700464 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700465 pdu_length));
Steve French46810cb2005-04-28 22:41:09 -0700466 if(server->tcpStatus == CifsNew) {
467 /* if nack on negprot (rather than
468 ret of smb negprot error) reconnecting
469 not going to help, ret error to mount */
470 break;
471 } else {
472 /* give server a second to
473 clean up before reconnect attempt */
474 msleep(1000);
475 /* always try 445 first on reconnect
476 since we get NACK on some if we ever
477 connected to port 139 (the NACK is
478 since we do not begin with RFC1001
479 session initialize frame) */
480 server->addr.sockAddr.sin_port =
481 htons(CIFS_PORT);
482 cifs_reconnect(server);
483 csocket = server->ssocket;
484 wake_up(&server->response_q);
485 continue;
486 }
Steve French70ca7342005-09-22 16:32:06 -0700487 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700488 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700489 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
490 length);
Steve French46810cb2005-04-28 22:41:09 -0700491 cifs_reconnect(server);
492 csocket = server->ssocket;
493 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700494 }
495
496 /* else we have an SMB response */
497 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700498 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700499 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700500 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700501 cifs_reconnect(server);
502 csocket = server->ssocket;
503 wake_up(&server->response_q);
504 continue;
505 }
506
507 /* else length ok */
508 reconnect = 0;
509
510 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
511 isLargeBuf = TRUE;
512 memcpy(bigbuf, smallbuf, 4);
513 smb_buffer = bigbuf;
514 }
515 length = 0;
516 iov.iov_base = 4 + (char *)smb_buffer;
517 iov.iov_len = pdu_length;
518 for (total_read = 0; total_read < pdu_length;
519 total_read += length) {
520 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
521 pdu_length - total_read, 0);
522 if((server->tcpStatus == CifsExiting) ||
523 (length == -EINTR)) {
524 /* then will exit */
525 reconnect = 2;
526 break;
527 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700528 cifs_reconnect(server);
529 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700530 /* Reconnect wakes up rspns q */
531 /* Now we will reread sock */
532 reconnect = 1;
533 break;
534 } else if ((length == -ERESTARTSYS) ||
535 (length == -EAGAIN)) {
536 msleep(1); /* minimum sleep to prevent looping,
537 allowing socket to clear and app
538 threads to set tcpStatus
539 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700540 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 } else if (length <= 0) {
542 cERROR(1,("Received no data, expecting %d",
543 pdu_length - total_read));
544 cifs_reconnect(server);
545 csocket = server->ssocket;
546 reconnect = 1;
547 break;
Steve French46810cb2005-04-28 22:41:09 -0700548 }
549 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700550 if(reconnect == 2)
551 break;
552 else if(reconnect == 1)
553 continue;
554
555 length += 4; /* account for rfc1002 hdr */
556
557
558 dump_smb(smb_buffer, length);
559 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700560 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700561 continue;
562 }
563
564
565 task_to_wake = NULL;
566 spin_lock(&GlobalMid_Lock);
567 list_for_each(tmp, &server->pending_mid_q) {
568 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
569
570 if ((mid_entry->mid == smb_buffer->Mid) &&
571 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
572 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700573 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
574 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700575 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700576 if(mid_entry->resp_buf) {
577 /* merge response - fix up 1st*/
578 if(coalesce_t2(smb_buffer,
579 mid_entry->resp_buf)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 break;
581 } else {
582 /* all parts received */
583 goto multi_t2_fnd;
584 }
585 } else {
586 if(!isLargeBuf) {
587 cERROR(1,("1st trans2 resp needs bigbuf"));
588 /* BB maybe we can fix this up, switch
589 to already allocated large buffer? */
590 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700591 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700592 mid_entry->resp_buf =
593 smb_buffer;
594 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 bigbuf = NULL;
596 }
597 }
598 break;
599 }
600 mid_entry->resp_buf = smb_buffer;
601 if(isLargeBuf)
602 mid_entry->largeBuf = 1;
603 else
604 mid_entry->largeBuf = 0;
605multi_t2_fnd:
606 task_to_wake = mid_entry->tsk;
607 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700608#ifdef CONFIG_CIFS_STATS2
609 mid_entry->when_received = jiffies;
610#endif
Steve Frenche4eb2952005-04-28 22:41:09 -0700611 break;
612 }
613 }
614 spin_unlock(&GlobalMid_Lock);
615 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700616 /* Was previous buf put in mpx struct for multi-rsp? */
617 if(!isMultiRsp) {
618 /* smb buffer will be freed by user thread */
619 if(isLargeBuf) {
620 bigbuf = NULL;
621 } else
622 smallbuf = NULL;
623 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700624 wake_up_process(task_to_wake);
Steve French57337e42005-04-28 22:41:10 -0700625 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700626 && (isMultiRsp == FALSE)) {
627 cERROR(1, ("No task to wake, unknown frame rcvd!"));
Steve French70ca7342005-09-22 16:32:06 -0700628 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
629 sizeof(struct smb_hdr));
Steve Frenche4eb2952005-04-28 22:41:09 -0700630 }
631 } /* end while !EXITING */
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 spin_lock(&GlobalMid_Lock);
634 server->tcpStatus = CifsExiting;
635 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700636 /* check if we have blocked requests that need to free */
637 /* Note that cifs_max_pending is normally 50, but
638 can be set at module install time to as little as two */
639 if(atomic_read(&server->inFlight) >= cifs_max_pending)
640 atomic_set(&server->inFlight, cifs_max_pending - 1);
641 /* We do not want to set the max_pending too low or we
642 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 spin_unlock(&GlobalMid_Lock);
644 /* Although there should not be any requests blocked on
645 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700646 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 to the same server - they now will see the session is in exit state
648 and get out of SendReceive. */
649 wake_up_all(&server->request_q);
650 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700651 msleep(125);
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 if(server->ssocket) {
654 sock_release(csocket);
655 server->ssocket = NULL;
656 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700657 /* buffer usuallly freed in free_mid - need to free it here on exit */
658 if (bigbuf != NULL)
659 cifs_buf_release(bigbuf);
660 if (smallbuf != NULL)
661 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
663 read_lock(&GlobalSMBSeslock);
664 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700665 /* loop through server session structures attached to this and
666 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 list_for_each(tmp, &GlobalSMBSessionList) {
668 ses =
669 list_entry(tmp, struct cifsSesInfo,
670 cifsSessionList);
671 if (ses->server == server) {
672 ses->status = CifsExiting;
673 ses->server = NULL;
674 }
675 }
676 read_unlock(&GlobalSMBSeslock);
677 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700678 /* although we can not zero the server struct pointer yet,
679 since there are active requests which may depnd on them,
680 mark the corresponding SMB sessions as exiting too */
681 list_for_each(tmp, &GlobalSMBSessionList) {
682 ses = list_entry(tmp, struct cifsSesInfo,
683 cifsSessionList);
684 if (ses->server == server) {
685 ses->status = CifsExiting;
686 }
687 }
688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 spin_lock(&GlobalMid_Lock);
690 list_for_each(tmp, &server->pending_mid_q) {
691 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
692 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
693 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700694 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 task_to_wake = mid_entry->tsk;
696 if(task_to_wake) {
697 wake_up_process(task_to_wake);
698 }
699 }
700 }
701 spin_unlock(&GlobalMid_Lock);
702 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700704 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 }
706
Steve Frenchf1914012005-08-18 09:37:34 -0700707 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 /* mpx threads have not exited yet give them
709 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700710 /* due to delays on oplock break requests, we need
711 to wait at least 45 seconds before giving up
712 on a request getting a response and going ahead
713 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700715 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /* if threads still have not exited they are probably never
717 coming home not much else we can do but free the memory */
718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 write_lock(&GlobalSMBSeslock);
721 atomic_dec(&tcpSesAllocCount);
722 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700723
724 /* last chance to mark ses pointers invalid
725 if there are any pointing to this (e.g
726 if a crazy root user tried to kill cifsd
727 kernel thread explicitly this might happen) */
728 list_for_each(tmp, &GlobalSMBSessionList) {
729 ses = list_entry(tmp, struct cifsSesInfo,
730 cifsSessionList);
731 if (ses->server == server) {
732 ses->server = NULL;
733 }
734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700736
737 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if(length > 0) {
739 mempool_resize(cifs_req_poolp,
740 length + cifs_min_rcv,
741 GFP_KERNEL);
742 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700743
Steve Frenchf1914012005-08-18 09:37:34 -0700744 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return 0;
746}
747
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748static int
749cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
750{
751 char *value;
752 char *data;
753 unsigned int temp_len, i, j;
754 char separator[2];
755
756 separator[0] = ',';
757 separator[1] = 0;
758
759 memset(vol->source_rfc1001_name,0x20,15);
760 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
761 /* does not have to be a perfect mapping since the field is
762 informational, only used for servers that do not support
763 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700764 vol->source_rfc1001_name[i] =
765 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700768 /* null target name indicates to use *SMBSERVR default called name
769 if we end up sending RFC1001 session initialize */
770 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 vol->linux_uid = current->uid; /* current->euid instead? */
772 vol->linux_gid = current->gid;
773 vol->dir_mode = S_IRWXUGO;
774 /* 2767 perms indicate mandatory locking support */
775 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
776
777 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
778 vol->rw = TRUE;
779
Jeremy Allisonac670552005-06-22 17:26:35 -0700780 /* default is always to request posix paths. */
781 vol->posix_paths = 1;
782
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (!options)
784 return 1;
785
786 if(strncmp(options,"sep=",4) == 0) {
787 if(options[4] != 0) {
788 separator[0] = options[4];
789 options += 5;
790 } else {
791 cFYI(1,("Null separator not allowed"));
792 }
793 }
794
795 while ((data = strsep(&options, separator)) != NULL) {
796 if (!*data)
797 continue;
798 if ((value = strchr(data, '=')) != NULL)
799 *value++ = '\0';
800
801 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
802 vol->no_xattr = 0;
803 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
804 vol->no_xattr = 1;
805 } else if (strnicmp(data, "user", 4) == 0) {
806 if (!value || !*value) {
807 printk(KERN_WARNING
808 "CIFS: invalid or missing username\n");
809 return 1; /* needs_arg; */
810 }
811 if (strnlen(value, 200) < 200) {
812 vol->username = value;
813 } else {
814 printk(KERN_WARNING "CIFS: username too long\n");
815 return 1;
816 }
817 } else if (strnicmp(data, "pass", 4) == 0) {
818 if (!value) {
819 vol->password = NULL;
820 continue;
821 } else if(value[0] == 0) {
822 /* check if string begins with double comma
823 since that would mean the password really
824 does start with a comma, and would not
825 indicate an empty string */
826 if(value[1] != separator[0]) {
827 vol->password = NULL;
828 continue;
829 }
830 }
831 temp_len = strlen(value);
832 /* removed password length check, NTLM passwords
833 can be arbitrarily long */
834
835 /* if comma in password, the string will be
836 prematurely null terminated. Commas in password are
837 specified across the cifs mount interface by a double
838 comma ie ,, and a comma used as in other cases ie ','
839 as a parameter delimiter/separator is single and due
840 to the strsep above is temporarily zeroed. */
841
842 /* NB: password legally can have multiple commas and
843 the only illegal character in a password is null */
844
Steve French09d1db52005-04-28 22:41:08 -0700845 if ((value[temp_len] == 0) &&
846 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 /* reinsert comma */
848 value[temp_len] = separator[0];
849 temp_len+=2; /* move after the second comma */
850 while(value[temp_len] != 0) {
851 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700852 if (value[temp_len+1] ==
853 separator[0]) {
854 /* skip second comma */
855 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 } else {
857 /* single comma indicating start
858 of next parm */
859 break;
860 }
861 }
862 temp_len++;
863 }
864 if(value[temp_len] == 0) {
865 options = NULL;
866 } else {
867 value[temp_len] = 0;
868 /* point option to start of next parm */
869 options = value + temp_len + 1;
870 }
871 /* go from value to value + temp_len condensing
872 double commas to singles. Note that this ends up
873 allocating a few bytes too many, which is ok */
Steve French433dc242005-04-28 22:41:08 -0700874 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
875 if(vol->password == NULL) {
876 printk("CIFS: no memory for pass\n");
877 return 1;
878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 for(i=0,j=0;i<temp_len;i++,j++) {
880 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700881 if(value[i] == separator[0]
882 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 /* skip second comma */
884 i++;
885 }
886 }
887 vol->password[j] = 0;
888 } else {
Steve French09d1db52005-04-28 22:41:08 -0700889 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700890 if(vol->password == NULL) {
891 printk("CIFS: no memory for pass\n");
892 return 1;
893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 strcpy(vol->password, value);
895 }
896 } else if (strnicmp(data, "ip", 2) == 0) {
897 if (!value || !*value) {
898 vol->UNCip = NULL;
899 } else if (strnlen(value, 35) < 35) {
900 vol->UNCip = value;
901 } else {
902 printk(KERN_WARNING "CIFS: ip address too long\n");
903 return 1;
904 }
905 } else if ((strnicmp(data, "unc", 3) == 0)
906 || (strnicmp(data, "target", 6) == 0)
907 || (strnicmp(data, "path", 4) == 0)) {
908 if (!value || !*value) {
909 printk(KERN_WARNING
910 "CIFS: invalid path to network resource\n");
911 return 1; /* needs_arg; */
912 }
913 if ((temp_len = strnlen(value, 300)) < 300) {
914 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
915 if(vol->UNC == NULL)
916 return 1;
917 strcpy(vol->UNC,value);
918 if (strncmp(vol->UNC, "//", 2) == 0) {
919 vol->UNC[0] = '\\';
920 vol->UNC[1] = '\\';
921 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
922 printk(KERN_WARNING
923 "CIFS: UNC Path does not begin with // or \\\\ \n");
924 return 1;
925 }
926 } else {
927 printk(KERN_WARNING "CIFS: UNC name too long\n");
928 return 1;
929 }
930 } else if ((strnicmp(data, "domain", 3) == 0)
931 || (strnicmp(data, "workgroup", 5) == 0)) {
932 if (!value || !*value) {
933 printk(KERN_WARNING "CIFS: invalid domain name\n");
934 return 1; /* needs_arg; */
935 }
936 /* BB are there cases in which a comma can be valid in
937 a domain name and need special handling? */
938 if (strnlen(value, 65) < 65) {
939 vol->domainname = value;
940 cFYI(1, ("Domain name set"));
941 } else {
942 printk(KERN_WARNING "CIFS: domain name too long\n");
943 return 1;
944 }
945 } else if (strnicmp(data, "iocharset", 9) == 0) {
946 if (!value || !*value) {
947 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
948 return 1; /* needs_arg; */
949 }
950 if (strnlen(value, 65) < 65) {
951 if(strnicmp(value,"default",7))
952 vol->iocharset = value;
953 /* if iocharset not set load_nls_default used by caller */
954 cFYI(1, ("iocharset set to %s",value));
955 } else {
956 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
957 return 1;
958 }
959 } else if (strnicmp(data, "uid", 3) == 0) {
960 if (value && *value) {
961 vol->linux_uid =
962 simple_strtoul(value, &value, 0);
963 }
964 } else if (strnicmp(data, "gid", 3) == 0) {
965 if (value && *value) {
966 vol->linux_gid =
967 simple_strtoul(value, &value, 0);
968 }
969 } else if (strnicmp(data, "file_mode", 4) == 0) {
970 if (value && *value) {
971 vol->file_mode =
972 simple_strtoul(value, &value, 0);
973 }
974 } else if (strnicmp(data, "dir_mode", 4) == 0) {
975 if (value && *value) {
976 vol->dir_mode =
977 simple_strtoul(value, &value, 0);
978 }
979 } else if (strnicmp(data, "dirmode", 4) == 0) {
980 if (value && *value) {
981 vol->dir_mode =
982 simple_strtoul(value, &value, 0);
983 }
984 } else if (strnicmp(data, "port", 4) == 0) {
985 if (value && *value) {
986 vol->port =
987 simple_strtoul(value, &value, 0);
988 }
989 } else if (strnicmp(data, "rsize", 5) == 0) {
990 if (value && *value) {
991 vol->rsize =
992 simple_strtoul(value, &value, 0);
993 }
994 } else if (strnicmp(data, "wsize", 5) == 0) {
995 if (value && *value) {
996 vol->wsize =
997 simple_strtoul(value, &value, 0);
998 }
999 } else if (strnicmp(data, "sockopt", 5) == 0) {
1000 if (value && *value) {
1001 vol->sockopt =
1002 simple_strtoul(value, &value, 0);
1003 }
1004 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1005 if (!value || !*value || (*value == ' ')) {
1006 cFYI(1,("invalid (empty) netbiosname specified"));
1007 } else {
1008 memset(vol->source_rfc1001_name,0x20,15);
1009 for(i=0;i<15;i++) {
1010 /* BB are there cases in which a comma can be
1011 valid in this workstation netbios name (and need
1012 special handling)? */
1013
1014 /* We do not uppercase netbiosname for user */
1015 if (value[i]==0)
1016 break;
1017 else
1018 vol->source_rfc1001_name[i] = value[i];
1019 }
1020 /* The string has 16th byte zero still from
1021 set at top of the function */
1022 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001023 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1024 }
1025 } else if (strnicmp(data, "servern", 7) == 0) {
1026 /* servernetbiosname specified override *SMBSERVER */
1027 if (!value || !*value || (*value == ' ')) {
1028 cFYI(1,("empty server netbiosname specified"));
1029 } else {
1030 /* last byte, type, is 0x20 for servr type */
1031 memset(vol->target_rfc1001_name,0x20,16);
1032
1033 for(i=0;i<15;i++) {
1034 /* BB are there cases in which a comma can be
1035 valid in this workstation netbios name (and need
1036 special handling)? */
1037
1038 /* user or mount helper must uppercase netbiosname */
1039 if (value[i]==0)
1040 break;
1041 else
1042 vol->target_rfc1001_name[i] = value[i];
1043 }
1044 /* The string has 16th byte zero still from
1045 set at top of the function */
1046 if((i==15) && (value[i] != 0))
1047 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 }
1049 } else if (strnicmp(data, "credentials", 4) == 0) {
1050 /* ignore */
1051 } else if (strnicmp(data, "version", 3) == 0) {
1052 /* ignore */
1053 } else if (strnicmp(data, "guest",5) == 0) {
1054 /* ignore */
1055 } else if (strnicmp(data, "rw", 2) == 0) {
1056 vol->rw = TRUE;
1057 } else if ((strnicmp(data, "suid", 4) == 0) ||
1058 (strnicmp(data, "nosuid", 6) == 0) ||
1059 (strnicmp(data, "exec", 4) == 0) ||
1060 (strnicmp(data, "noexec", 6) == 0) ||
1061 (strnicmp(data, "nodev", 5) == 0) ||
1062 (strnicmp(data, "noauto", 6) == 0) ||
1063 (strnicmp(data, "dev", 3) == 0)) {
1064 /* The mount tool or mount.cifs helper (if present)
1065 uses these opts to set flags, and the flags are read
1066 by the kernel vfs layer before we get here (ie
1067 before read super) so there is no point trying to
1068 parse these options again and set anything and it
1069 is ok to just ignore them */
1070 continue;
1071 } else if (strnicmp(data, "ro", 2) == 0) {
1072 vol->rw = FALSE;
1073 } else if (strnicmp(data, "hard", 4) == 0) {
1074 vol->retry = 1;
1075 } else if (strnicmp(data, "soft", 4) == 0) {
1076 vol->retry = 0;
1077 } else if (strnicmp(data, "perm", 4) == 0) {
1078 vol->noperm = 0;
1079 } else if (strnicmp(data, "noperm", 6) == 0) {
1080 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001081 } else if (strnicmp(data, "mapchars", 8) == 0) {
1082 vol->remap = 1;
1083 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1084 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001085 } else if (strnicmp(data, "sfu", 3) == 0) {
1086 vol->sfu_emul = 1;
1087 } else if (strnicmp(data, "nosfu", 5) == 0) {
1088 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001089 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1090 vol->posix_paths = 1;
1091 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1092 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001093 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1094 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001095 vol->nocase = 1;
1096 } else if (strnicmp(data, "brl", 3) == 0) {
1097 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001098 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001099 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001100 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001101 /* turn off mandatory locking in mode
1102 if remote locking is turned off since the
1103 local vfs will do advisory */
1104 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1105 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 } else if (strnicmp(data, "setuids", 7) == 0) {
1107 vol->setuids = 1;
1108 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1109 vol->setuids = 0;
1110 } else if (strnicmp(data, "nohard", 6) == 0) {
1111 vol->retry = 0;
1112 } else if (strnicmp(data, "nosoft", 6) == 0) {
1113 vol->retry = 1;
1114 } else if (strnicmp(data, "nointr", 6) == 0) {
1115 vol->intr = 0;
1116 } else if (strnicmp(data, "intr", 4) == 0) {
1117 vol->intr = 1;
1118 } else if (strnicmp(data, "serverino",7) == 0) {
1119 vol->server_ino = 1;
1120 } else if (strnicmp(data, "noserverino",9) == 0) {
1121 vol->server_ino = 0;
1122 } else if (strnicmp(data, "acl",3) == 0) {
1123 vol->no_psx_acl = 0;
1124 } else if (strnicmp(data, "noacl",5) == 0) {
1125 vol->no_psx_acl = 1;
1126 } else if (strnicmp(data, "direct",6) == 0) {
1127 vol->direct_io = 1;
1128 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1129 vol->direct_io = 1;
1130 } else if (strnicmp(data, "in6_addr",8) == 0) {
1131 if (!value || !*value) {
1132 vol->in6_addr = NULL;
1133 } else if (strnlen(value, 49) == 48) {
1134 vol->in6_addr = value;
1135 } else {
1136 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1137 return 1;
1138 }
1139 } else if (strnicmp(data, "noac", 4) == 0) {
1140 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1141 } else
1142 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1143 }
1144 if (vol->UNC == NULL) {
1145 if(devname == NULL) {
1146 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1147 return 1;
1148 }
1149 if ((temp_len = strnlen(devname, 300)) < 300) {
1150 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1151 if(vol->UNC == NULL)
1152 return 1;
1153 strcpy(vol->UNC,devname);
1154 if (strncmp(vol->UNC, "//", 2) == 0) {
1155 vol->UNC[0] = '\\';
1156 vol->UNC[1] = '\\';
1157 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1158 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1159 return 1;
1160 }
1161 } else {
1162 printk(KERN_WARNING "CIFS: UNC name too long\n");
1163 return 1;
1164 }
1165 }
1166 if(vol->UNCip == NULL)
1167 vol->UNCip = &vol->UNC[2];
1168
1169 return 0;
1170}
1171
1172static struct cifsSesInfo *
1173cifs_find_tcp_session(struct in_addr * target_ip_addr,
1174 struct in6_addr *target_ip6_addr,
1175 char *userName, struct TCP_Server_Info **psrvTcp)
1176{
1177 struct list_head *tmp;
1178 struct cifsSesInfo *ses;
1179 *psrvTcp = NULL;
1180 read_lock(&GlobalSMBSeslock);
1181
1182 list_for_each(tmp, &GlobalSMBSessionList) {
1183 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1184 if (ses->server) {
1185 if((target_ip_addr &&
1186 (ses->server->addr.sockAddr.sin_addr.s_addr
1187 == target_ip_addr->s_addr)) || (target_ip6_addr
1188 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1189 target_ip6_addr,sizeof(*target_ip6_addr)))){
1190 /* BB lock server and tcp session and increment use count here?? */
1191 *psrvTcp = ses->server; /* found a match on the TCP session */
1192 /* BB check if reconnection needed */
1193 if (strncmp
1194 (ses->userName, userName,
1195 MAX_USERNAME_SIZE) == 0){
1196 read_unlock(&GlobalSMBSeslock);
1197 return ses; /* found exact match on both tcp and SMB sessions */
1198 }
1199 }
1200 }
1201 /* else tcp and smb sessions need reconnection */
1202 }
1203 read_unlock(&GlobalSMBSeslock);
1204 return NULL;
1205}
1206
1207static struct cifsTconInfo *
1208find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1209{
1210 struct list_head *tmp;
1211 struct cifsTconInfo *tcon;
1212
1213 read_lock(&GlobalSMBSeslock);
1214 list_for_each(tmp, &GlobalTreeConnectionList) {
1215 cFYI(1, ("Next tcon - "));
1216 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1217 if (tcon->ses) {
1218 if (tcon->ses->server) {
1219 cFYI(1,
1220 (" old ip addr: %x == new ip %x ?",
1221 tcon->ses->server->addr.sockAddr.sin_addr.
1222 s_addr, new_target_ip_addr));
1223 if (tcon->ses->server->addr.sockAddr.sin_addr.
1224 s_addr == new_target_ip_addr) {
1225 /* BB lock tcon and server and tcp session and increment use count here? */
1226 /* found a match on the TCP session */
1227 /* BB check if reconnection needed */
1228 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1229 tcon->treeName, uncName));
1230 if (strncmp
1231 (tcon->treeName, uncName,
1232 MAX_TREE_SIZE) == 0) {
1233 cFYI(1,
1234 ("Matched UNC, old user: %s == new: %s ?",
1235 tcon->treeName, uncName));
1236 if (strncmp
1237 (tcon->ses->userName,
1238 userName,
1239 MAX_USERNAME_SIZE) == 0) {
1240 read_unlock(&GlobalSMBSeslock);
1241 return tcon;/* also matched user (smb session)*/
1242 }
1243 }
1244 }
1245 }
1246 }
1247 }
1248 read_unlock(&GlobalSMBSeslock);
1249 return NULL;
1250}
1251
1252int
1253connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001254 const char *old_path, const struct nls_table *nls_codepage,
1255 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256{
1257 unsigned char *referrals = NULL;
1258 unsigned int num_referrals;
1259 int rc = 0;
1260
1261 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001262 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
1264 /* BB Add in code to: if valid refrl, if not ip address contact
1265 the helper that resolves tcp names, mount to it, try to
1266 tcon to it unmount it if fail */
1267
1268 if(referrals)
1269 kfree(referrals);
1270
1271 return rc;
1272}
1273
1274int
1275get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1276 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001277 unsigned int *pnum_referrals,
1278 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
1280 char *temp_unc;
1281 int rc = 0;
1282
1283 *pnum_referrals = 0;
1284
1285 if (pSesInfo->ipc_tid == 0) {
1286 temp_unc = kmalloc(2 /* for slashes */ +
1287 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1288 + 1 + 4 /* slash IPC$ */ + 2,
1289 GFP_KERNEL);
1290 if (temp_unc == NULL)
1291 return -ENOMEM;
1292 temp_unc[0] = '\\';
1293 temp_unc[1] = '\\';
1294 strcpy(temp_unc + 2, pSesInfo->serverName);
1295 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1296 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1297 cFYI(1,
1298 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1299 kfree(temp_unc);
1300 }
1301 if (rc == 0)
1302 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001303 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
1305 return rc;
1306}
1307
1308/* See RFC1001 section 14 on representation of Netbios names */
1309static void rfc1002mangle(char * target,char * source, unsigned int length)
1310{
1311 unsigned int i,j;
1312
1313 for(i=0,j=0;i<(length);i++) {
1314 /* mask a nibble at a time and encode */
1315 target[j] = 'A' + (0x0F & (source[i] >> 4));
1316 target[j+1] = 'A' + (0x0F & source[i]);
1317 j+=2;
1318 }
1319
1320}
1321
1322
1323static int
1324ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001325 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
1327 int rc = 0;
1328 int connected = 0;
1329 __be16 orig_port = 0;
1330
1331 if(*csocket == NULL) {
1332 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1333 if (rc < 0) {
1334 cERROR(1, ("Error %d creating socket",rc));
1335 *csocket = NULL;
1336 return rc;
1337 } else {
1338 /* BB other socket options to set KEEPALIVE, NODELAY? */
1339 cFYI(1,("Socket created"));
1340 (*csocket)->sk->sk_allocation = GFP_NOFS;
1341 }
1342 }
1343
1344 psin_server->sin_family = AF_INET;
1345 if(psin_server->sin_port) { /* user overrode default port */
1346 rc = (*csocket)->ops->connect(*csocket,
1347 (struct sockaddr *) psin_server,
1348 sizeof (struct sockaddr_in),0);
1349 if (rc >= 0)
1350 connected = 1;
1351 }
1352
1353 if(!connected) {
1354 /* save original port so we can retry user specified port
1355 later if fall back ports fail this time */
1356 orig_port = psin_server->sin_port;
1357
1358 /* do not retry on the same port we just failed on */
1359 if(psin_server->sin_port != htons(CIFS_PORT)) {
1360 psin_server->sin_port = htons(CIFS_PORT);
1361
1362 rc = (*csocket)->ops->connect(*csocket,
1363 (struct sockaddr *) psin_server,
1364 sizeof (struct sockaddr_in),0);
1365 if (rc >= 0)
1366 connected = 1;
1367 }
1368 }
1369 if (!connected) {
1370 psin_server->sin_port = htons(RFC1001_PORT);
1371 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1372 psin_server, sizeof (struct sockaddr_in),0);
1373 if (rc >= 0)
1374 connected = 1;
1375 }
1376
1377 /* give up here - unless we want to retry on different
1378 protocol families some day */
1379 if (!connected) {
1380 if(orig_port)
1381 psin_server->sin_port = orig_port;
1382 cFYI(1,("Error %d connecting to server via ipv4",rc));
1383 sock_release(*csocket);
1384 *csocket = NULL;
1385 return rc;
1386 }
1387 /* Eventually check for other socket options to change from
1388 the default. sock_setsockopt not used because it expects
1389 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001390 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1391 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001393 /* make the bufsizes depend on wsize/rsize and max requests */
1394 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1395 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1396 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1397 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Steve Frenchb387eae2005-10-10 14:21:15 -07001399 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1401 /* some servers require RFC1001 sessinit before sending
1402 negprot - BB check reconnection in case where second
1403 sessinit is sent but no second negprot */
1404 struct rfc1002_session_packet * ses_init_buf;
1405 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001406 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if(ses_init_buf) {
1408 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001409 if(target_name && (target_name[0] != 0)) {
1410 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1411 target_name, 16);
1412 } else {
1413 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1414 DEFAULT_CIFS_CALLED_NAME,16);
1415 }
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 ses_init_buf->trailer.session_req.calling_len = 32;
1418 /* calling name ends in null (byte 16) from old smb
1419 convention. */
1420 if(netbios_name && (netbios_name[0] !=0)) {
1421 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1422 netbios_name,16);
1423 } else {
1424 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1425 "LINUX_CIFS_CLNT",16);
1426 }
1427 ses_init_buf->trailer.session_req.scope1 = 0;
1428 ses_init_buf->trailer.session_req.scope2 = 0;
1429 smb_buf = (struct smb_hdr *)ses_init_buf;
1430 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1431 smb_buf->smb_buf_length = 0x81000044;
1432 rc = smb_send(*csocket, smb_buf, 0x44,
1433 (struct sockaddr *)psin_server);
1434 kfree(ses_init_buf);
1435 }
1436 /* else the negprot may still work without this
1437 even though malloc failed */
1438
1439 }
1440
1441 return rc;
1442}
1443
1444static int
1445ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1446{
1447 int rc = 0;
1448 int connected = 0;
1449 __be16 orig_port = 0;
1450
1451 if(*csocket == NULL) {
1452 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1453 if (rc < 0) {
1454 cERROR(1, ("Error %d creating ipv6 socket",rc));
1455 *csocket = NULL;
1456 return rc;
1457 } else {
1458 /* BB other socket options to set KEEPALIVE, NODELAY? */
1459 cFYI(1,("ipv6 Socket created"));
1460 (*csocket)->sk->sk_allocation = GFP_NOFS;
1461 }
1462 }
1463
1464 psin_server->sin6_family = AF_INET6;
1465
1466 if(psin_server->sin6_port) { /* user overrode default port */
1467 rc = (*csocket)->ops->connect(*csocket,
1468 (struct sockaddr *) psin_server,
1469 sizeof (struct sockaddr_in6),0);
1470 if (rc >= 0)
1471 connected = 1;
1472 }
1473
1474 if(!connected) {
1475 /* save original port so we can retry user specified port
1476 later if fall back ports fail this time */
1477
1478 orig_port = psin_server->sin6_port;
1479 /* do not retry on the same port we just failed on */
1480 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1481 psin_server->sin6_port = htons(CIFS_PORT);
1482
1483 rc = (*csocket)->ops->connect(*csocket,
1484 (struct sockaddr *) psin_server,
1485 sizeof (struct sockaddr_in6),0);
1486 if (rc >= 0)
1487 connected = 1;
1488 }
1489 }
1490 if (!connected) {
1491 psin_server->sin6_port = htons(RFC1001_PORT);
1492 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1493 psin_server, sizeof (struct sockaddr_in6),0);
1494 if (rc >= 0)
1495 connected = 1;
1496 }
1497
1498 /* give up here - unless we want to retry on different
1499 protocol families some day */
1500 if (!connected) {
1501 if(orig_port)
1502 psin_server->sin6_port = orig_port;
1503 cFYI(1,("Error %d connecting to server via ipv6",rc));
1504 sock_release(*csocket);
1505 *csocket = NULL;
1506 return rc;
1507 }
1508 /* Eventually check for other socket options to change from
1509 the default. sock_setsockopt not used because it expects
1510 user space buffer */
1511 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1512
1513 return rc;
1514}
1515
1516int
1517cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1518 char *mount_data, const char *devname)
1519{
1520 int rc = 0;
1521 int xid;
1522 int address_type = AF_INET;
1523 struct socket *csocket = NULL;
1524 struct sockaddr_in sin_server;
1525 struct sockaddr_in6 sin_server6;
1526 struct smb_vol volume_info;
1527 struct cifsSesInfo *pSesInfo = NULL;
1528 struct cifsSesInfo *existingCifsSes = NULL;
1529 struct cifsTconInfo *tcon = NULL;
1530 struct TCP_Server_Info *srvTcp = NULL;
1531
1532 xid = GetXid();
1533
1534/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1535
1536 memset(&volume_info,0,sizeof(struct smb_vol));
1537 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1538 if(volume_info.UNC)
1539 kfree(volume_info.UNC);
1540 if(volume_info.password)
1541 kfree(volume_info.password);
1542 FreeXid(xid);
1543 return -EINVAL;
1544 }
1545
1546 if (volume_info.username) {
1547 /* BB fixme parse for domain name here */
1548 cFYI(1, ("Username: %s ", volume_info.username));
1549
1550 } else {
1551 cifserror("No username specified ");
1552 /* In userspace mount helper we can get user name from alternate
1553 locations such as env variables and files on disk */
1554 if(volume_info.UNC)
1555 kfree(volume_info.UNC);
1556 if(volume_info.password)
1557 kfree(volume_info.password);
1558 FreeXid(xid);
1559 return -EINVAL;
1560 }
1561
1562 if (volume_info.UNCip && volume_info.UNC) {
1563 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1564
1565 if(rc <= 0) {
1566 /* not ipv4 address, try ipv6 */
1567 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1568 if(rc > 0)
1569 address_type = AF_INET6;
1570 } else {
1571 address_type = AF_INET;
1572 }
1573
1574 if(rc <= 0) {
1575 /* we failed translating address */
1576 if(volume_info.UNC)
1577 kfree(volume_info.UNC);
1578 if(volume_info.password)
1579 kfree(volume_info.password);
1580 FreeXid(xid);
1581 return -EINVAL;
1582 }
1583
1584 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1585 /* success */
1586 rc = 0;
1587 } else if (volume_info.UNCip){
1588 /* BB using ip addr as server name connect to the DFS root below */
1589 cERROR(1,("Connecting to DFS root not implemented yet"));
1590 if(volume_info.UNC)
1591 kfree(volume_info.UNC);
1592 if(volume_info.password)
1593 kfree(volume_info.password);
1594 FreeXid(xid);
1595 return -EINVAL;
1596 } else /* which servers DFS root would we conect to */ {
1597 cERROR(1,
1598 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1599 if(volume_info.UNC)
1600 kfree(volume_info.UNC);
1601 if(volume_info.password)
1602 kfree(volume_info.password);
1603 FreeXid(xid);
1604 return -EINVAL;
1605 }
1606
1607 /* this is needed for ASCII cp to Unicode converts */
1608 if(volume_info.iocharset == NULL) {
1609 cifs_sb->local_nls = load_nls_default();
1610 /* load_nls_default can not return null */
1611 } else {
1612 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1613 if(cifs_sb->local_nls == NULL) {
1614 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1615 if(volume_info.UNC)
1616 kfree(volume_info.UNC);
1617 if(volume_info.password)
1618 kfree(volume_info.password);
1619 FreeXid(xid);
1620 return -ELIBACC;
1621 }
1622 }
1623
1624 if(address_type == AF_INET)
1625 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1626 NULL /* no ipv6 addr */,
1627 volume_info.username, &srvTcp);
1628 else if(address_type == AF_INET6)
1629 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1630 &sin_server6.sin6_addr,
1631 volume_info.username, &srvTcp);
1632 else {
1633 if(volume_info.UNC)
1634 kfree(volume_info.UNC);
1635 if(volume_info.password)
1636 kfree(volume_info.password);
1637 FreeXid(xid);
1638 return -EINVAL;
1639 }
1640
1641
1642 if (srvTcp) {
1643 cFYI(1, ("Existing tcp session with server found "));
1644 } else { /* create socket */
1645 if(volume_info.port)
1646 sin_server.sin_port = htons(volume_info.port);
1647 else
1648 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001649 rc = ipv4_connect(&sin_server,&csocket,
1650 volume_info.source_rfc1001_name,
1651 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 if (rc < 0) {
1653 cERROR(1,
1654 ("Error connecting to IPv4 socket. Aborting operation"));
1655 if(csocket != NULL)
1656 sock_release(csocket);
1657 if(volume_info.UNC)
1658 kfree(volume_info.UNC);
1659 if(volume_info.password)
1660 kfree(volume_info.password);
1661 FreeXid(xid);
1662 return rc;
1663 }
1664
1665 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1666 if (srvTcp == NULL) {
1667 rc = -ENOMEM;
1668 sock_release(csocket);
1669 if(volume_info.UNC)
1670 kfree(volume_info.UNC);
1671 if(volume_info.password)
1672 kfree(volume_info.password);
1673 FreeXid(xid);
1674 return rc;
1675 } else {
1676 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1677 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1678 atomic_set(&srvTcp->inFlight,0);
1679 /* BB Add code for ipv6 case too */
1680 srvTcp->ssocket = csocket;
1681 srvTcp->protocolType = IPV4;
1682 init_waitqueue_head(&srvTcp->response_q);
1683 init_waitqueue_head(&srvTcp->request_q);
1684 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1685 /* at this point we are the only ones with the pointer
1686 to the struct since the kernel thread not created yet
1687 so no need to spinlock this init of tcpStatus */
1688 srvTcp->tcpStatus = CifsNew;
1689 init_MUTEX(&srvTcp->tcpSem);
1690 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1691 CLONE_FS | CLONE_FILES | CLONE_VM);
1692 if(rc < 0) {
1693 rc = -ENOMEM;
1694 sock_release(csocket);
1695 if(volume_info.UNC)
1696 kfree(volume_info.UNC);
1697 if(volume_info.password)
1698 kfree(volume_info.password);
1699 FreeXid(xid);
1700 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001701 }
1702 wait_for_completion(&cifsd_complete);
1703 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001705 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001706 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 }
1708 }
1709
1710 if (existingCifsSes) {
1711 pSesInfo = existingCifsSes;
1712 cFYI(1, ("Existing smb sess found "));
1713 if(volume_info.password)
1714 kfree(volume_info.password);
1715 /* volume_info.UNC freed at end of function */
1716 } else if (!rc) {
1717 cFYI(1, ("Existing smb sess not found "));
1718 pSesInfo = sesInfoAlloc();
1719 if (pSesInfo == NULL)
1720 rc = -ENOMEM;
1721 else {
1722 pSesInfo->server = srvTcp;
1723 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1724 NIPQUAD(sin_server.sin_addr.s_addr));
1725 }
1726
1727 if (!rc){
1728 /* volume_info.password freed at unmount */
1729 if (volume_info.password)
1730 pSesInfo->password = volume_info.password;
1731 if (volume_info.username)
1732 strncpy(pSesInfo->userName,
1733 volume_info.username,MAX_USERNAME_SIZE);
1734 if (volume_info.domainname)
1735 strncpy(pSesInfo->domainName,
1736 volume_info.domainname,MAX_USERNAME_SIZE);
1737 pSesInfo->linux_uid = volume_info.linux_uid;
1738 down(&pSesInfo->sesSem);
1739 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1740 up(&pSesInfo->sesSem);
1741 if(!rc)
1742 atomic_inc(&srvTcp->socketUseCount);
1743 } else
1744 if(volume_info.password)
1745 kfree(volume_info.password);
1746 }
1747
1748 /* search for existing tcon to this server share */
1749 if (!rc) {
Steve French0ae0efa2005-10-10 10:57:19 -07001750 if(volume_info.rsize > CIFSMaxBufSize) {
1751 cERROR(1,("rsize %d too large, using MaxBufSize",
1752 volume_info.rsize));
1753 cifs_sb->rsize = CIFSMaxBufSize;
1754 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001756 else /* default */
1757 cifs_sb->rsize = CIFSMaxBufSize;
1758
1759 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1760 cERROR(1,("wsize %d too large using 4096 instead",
1761 volume_info.wsize));
1762 cifs_sb->wsize = 4096;
1763 } else if(volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 cifs_sb->wsize = volume_info.wsize;
1765 else
1766 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1767 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
Steve French6b8edfe2005-08-23 20:26:03 -07001768 cifs_sb->rsize = PAGE_CACHE_SIZE;
1769 /* Windows ME does this */
1770 cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
1772 cifs_sb->mnt_uid = volume_info.linux_uid;
1773 cifs_sb->mnt_gid = volume_info.linux_gid;
1774 cifs_sb->mnt_file_mode = volume_info.file_mode;
1775 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1776 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1777
1778 if(volume_info.noperm)
1779 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1780 if(volume_info.setuids)
1781 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1782 if(volume_info.server_ino)
1783 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001784 if(volume_info.remap)
1785 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 if(volume_info.no_xattr)
1787 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001788 if(volume_info.sfu_emul)
1789 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001790 if(volume_info.nobrl)
1791 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001794 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1796 }
1797
1798 tcon =
1799 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1800 volume_info.username);
1801 if (tcon) {
1802 cFYI(1, ("Found match on UNC path "));
1803 /* we can have only one retry value for a connection
1804 to a share so for resources mounted more than once
1805 to the same server share the last value passed in
1806 for the retry flag is used */
1807 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001808 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 } else {
1810 tcon = tconInfoAlloc();
1811 if (tcon == NULL)
1812 rc = -ENOMEM;
1813 else {
1814 /* check for null share name ie connect to dfs root */
1815
1816 /* BB check if this works for exactly length three strings */
1817 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1818 && (strchr(volume_info.UNC + 3, '/') ==
1819 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001820 rc = connect_to_dfs_path(xid, pSesInfo,
1821 "", cifs_sb->local_nls,
1822 cifs_sb->mnt_cifs_flags &
1823 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 if(volume_info.UNC)
1825 kfree(volume_info.UNC);
1826 FreeXid(xid);
1827 return -ENODEV;
1828 } else {
1829 rc = CIFSTCon(xid, pSesInfo,
1830 volume_info.UNC,
1831 tcon, cifs_sb->local_nls);
1832 cFYI(1, ("CIFS Tcon rc = %d", rc));
1833 }
1834 if (!rc) {
1835 atomic_inc(&pSesInfo->inUse);
1836 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001837 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 }
1839 }
1840 }
1841 }
1842 if(pSesInfo) {
1843 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1844 sb->s_maxbytes = (u64) 1 << 63;
1845 } else
1846 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1847 }
1848
1849 sb->s_time_gran = 100;
1850
1851/* on error free sesinfo and tcon struct if needed */
1852 if (rc) {
1853 /* if session setup failed, use count is zero but
1854 we still need to free cifsd thread */
1855 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1856 spin_lock(&GlobalMid_Lock);
1857 srvTcp->tcpStatus = CifsExiting;
1858 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001859 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001861 wait_for_completion(&cifsd_complete);
1862 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 }
1864 /* If find_unc succeeded then rc == 0 so we can not end */
1865 if (tcon) /* up accidently freeing someone elses tcon struct */
1866 tconInfoFree(tcon);
1867 if (existingCifsSes == NULL) {
1868 if (pSesInfo) {
1869 if ((pSesInfo->server) &&
1870 (pSesInfo->status == CifsGood)) {
1871 int temp_rc;
1872 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1873 /* if the socketUseCount is now zero */
1874 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001875 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001877 wait_for_completion(&cifsd_complete);
1878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 } else
1880 cFYI(1, ("No session or bad tcon"));
1881 sesInfoFree(pSesInfo);
1882 /* pSesInfo = NULL; */
1883 }
1884 }
1885 } else {
1886 atomic_inc(&tcon->useCount);
1887 cifs_sb->tcon = tcon;
1888 tcon->ses = pSesInfo;
1889
1890 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001891 CIFSSMBQFSDeviceInfo(xid, tcon);
1892 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001894 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if(!volume_info.no_psx_acl) {
1896 if(CIFS_UNIX_POSIX_ACL_CAP &
1897 le64_to_cpu(tcon->fsUnixInfo.Capability))
1898 cFYI(1,("server negotiated posix acl support"));
1899 sb->s_flags |= MS_POSIXACL;
1900 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001901
1902 /* Try and negotiate POSIX pathnames if we can. */
1903 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1904 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French45abc6e2005-06-23 13:42:03 -05001905 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
Jeremy Allisonac670552005-06-22 17:26:35 -07001906 cFYI(1,("negotiated posix pathnames support"));
1907 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1908 } else {
1909 cFYI(1,("posix pathnames support requested but not supported"));
1910 }
1911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 }
1913 }
Steve French3e844692005-10-03 13:37:24 -07001914 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
1915 cifs_sb->wsize = min(cifs_sb->wsize,
1916 (tcon->ses->server->maxBuf -
1917 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07001918 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
1919 cifs_sb->rsize = min(cifs_sb->rsize,
1920 (tcon->ses->server->maxBuf -
1921 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 }
1923
1924 /* volume_info.password is freed above when existing session found
1925 (in which case it is not needed anymore) but when new sesion is created
1926 the password ptr is put in the new session structure (in which case the
1927 password will be freed at unmount time) */
1928 if(volume_info.UNC)
1929 kfree(volume_info.UNC);
1930 FreeXid(xid);
1931 return rc;
1932}
1933
1934static int
1935CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1936 char session_key[CIFS_SESSION_KEY_SIZE],
1937 const struct nls_table *nls_codepage)
1938{
1939 struct smb_hdr *smb_buffer;
1940 struct smb_hdr *smb_buffer_response;
1941 SESSION_SETUP_ANDX *pSMB;
1942 SESSION_SETUP_ANDX *pSMBr;
1943 char *bcc_ptr;
1944 char *user;
1945 char *domain;
1946 int rc = 0;
1947 int remaining_words = 0;
1948 int bytes_returned = 0;
1949 int len;
1950 __u32 capabilities;
1951 __u16 count;
1952
1953 cFYI(1, ("In sesssetup "));
1954 if(ses == NULL)
1955 return -EINVAL;
1956 user = ses->userName;
1957 domain = ses->domainName;
1958 smb_buffer = cifs_buf_get();
1959 if (smb_buffer == NULL) {
1960 return -ENOMEM;
1961 }
1962 smb_buffer_response = smb_buffer;
1963 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1964
1965 /* send SMBsessionSetup here */
1966 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1967 NULL /* no tCon exists yet */ , 13 /* wct */ );
1968
Steve French1982c342005-08-17 12:38:22 -07001969 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 pSMB->req_no_secext.AndXCommand = 0xFF;
1971 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1972 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1973
1974 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1975 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1976
1977 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1978 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1979 if (ses->capabilities & CAP_UNICODE) {
1980 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1981 capabilities |= CAP_UNICODE;
1982 }
1983 if (ses->capabilities & CAP_STATUS32) {
1984 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1985 capabilities |= CAP_STATUS32;
1986 }
1987 if (ses->capabilities & CAP_DFS) {
1988 smb_buffer->Flags2 |= SMBFLG2_DFS;
1989 capabilities |= CAP_DFS;
1990 }
1991 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1992
1993 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1994 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1995
1996 pSMB->req_no_secext.CaseSensitivePasswordLength =
1997 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1998 bcc_ptr = pByteArea(smb_buffer);
1999 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
2000 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2001 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
2002 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2003
2004 if (ses->capabilities & CAP_UNICODE) {
2005 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2006 *bcc_ptr = 0;
2007 bcc_ptr++;
2008 }
2009 if(user == NULL)
2010 bytes_returned = 0; /* skill null user */
2011 else
2012 bytes_returned =
2013 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
2014 nls_codepage);
2015 /* convert number of 16 bit words to bytes */
2016 bcc_ptr += 2 * bytes_returned;
2017 bcc_ptr += 2; /* trailing null */
2018 if (domain == NULL)
2019 bytes_returned =
2020 cifs_strtoUCS((wchar_t *) bcc_ptr,
2021 "CIFS_LINUX_DOM", 32, nls_codepage);
2022 else
2023 bytes_returned =
2024 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2025 nls_codepage);
2026 bcc_ptr += 2 * bytes_returned;
2027 bcc_ptr += 2;
2028 bytes_returned =
2029 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2030 32, nls_codepage);
2031 bcc_ptr += 2 * bytes_returned;
2032 bytes_returned =
2033 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
2034 32, nls_codepage);
2035 bcc_ptr += 2 * bytes_returned;
2036 bcc_ptr += 2;
2037 bytes_returned =
2038 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2039 64, nls_codepage);
2040 bcc_ptr += 2 * bytes_returned;
2041 bcc_ptr += 2;
2042 } else {
2043 if(user != NULL) {
2044 strncpy(bcc_ptr, user, 200);
2045 bcc_ptr += strnlen(user, 200);
2046 }
2047 *bcc_ptr = 0;
2048 bcc_ptr++;
2049 if (domain == NULL) {
2050 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2051 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2052 } else {
2053 strncpy(bcc_ptr, domain, 64);
2054 bcc_ptr += strnlen(domain, 64);
2055 *bcc_ptr = 0;
2056 bcc_ptr++;
2057 }
2058 strcpy(bcc_ptr, "Linux version ");
2059 bcc_ptr += strlen("Linux version ");
2060 strcpy(bcc_ptr, system_utsname.release);
2061 bcc_ptr += strlen(system_utsname.release) + 1;
2062 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2063 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2064 }
2065 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2066 smb_buffer->smb_buf_length += count;
2067 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2068
2069 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2070 &bytes_returned, 1);
2071 if (rc) {
2072/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2073 } else if ((smb_buffer_response->WordCount == 3)
2074 || (smb_buffer_response->WordCount == 4)) {
2075 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2076 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2077 if (action & GUEST_LOGIN)
2078 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2079 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2080 cFYI(1, ("UID = %d ", ses->Suid));
2081 /* response can have either 3 or 4 word count - Samba sends 3 */
2082 bcc_ptr = pByteArea(smb_buffer_response);
2083 if ((pSMBr->resp.hdr.WordCount == 3)
2084 || ((pSMBr->resp.hdr.WordCount == 4)
2085 && (blob_len < pSMBr->resp.ByteCount))) {
2086 if (pSMBr->resp.hdr.WordCount == 4)
2087 bcc_ptr += blob_len;
2088
2089 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2090 if ((long) (bcc_ptr) % 2) {
2091 remaining_words =
2092 (BCC(smb_buffer_response) - 1) /2;
2093 bcc_ptr++; /* Unicode strings must be word aligned */
2094 } else {
2095 remaining_words =
2096 BCC(smb_buffer_response) / 2;
2097 }
2098 len =
2099 UniStrnlen((wchar_t *) bcc_ptr,
2100 remaining_words - 1);
2101/* We look for obvious messed up bcc or strings in response so we do not go off
2102 the end since (at least) WIN2K and Windows XP have a major bug in not null
2103 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07002104 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2105 if(ses->serverOS == NULL)
2106 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 cifs_strfromUCS_le(ses->serverOS,
2108 (wchar_t *)bcc_ptr, len,nls_codepage);
2109 bcc_ptr += 2 * (len + 1);
2110 remaining_words -= len + 1;
2111 ses->serverOS[2 * len] = 0;
2112 ses->serverOS[1 + (2 * len)] = 0;
2113 if (remaining_words > 0) {
2114 len = UniStrnlen((wchar_t *)bcc_ptr,
2115 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07002116 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2117 if(ses->serverNOS == NULL)
2118 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 cifs_strfromUCS_le(ses->serverNOS,
2120 (wchar_t *)bcc_ptr,len,nls_codepage);
2121 bcc_ptr += 2 * (len + 1);
2122 ses->serverNOS[2 * len] = 0;
2123 ses->serverNOS[1 + (2 * len)] = 0;
2124 if(strncmp(ses->serverNOS,
2125 "NT LAN Manager 4",16) == 0) {
2126 cFYI(1,("NT4 server"));
2127 ses->flags |= CIFS_SES_NT4;
2128 }
2129 remaining_words -= len + 1;
2130 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002131 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2133 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002134 kcalloc(1, 2*(len+1),GFP_KERNEL);
2135 if(ses->serverDomain == NULL)
2136 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 cifs_strfromUCS_le(ses->serverDomain,
2138 (wchar_t *)bcc_ptr,len,nls_codepage);
2139 bcc_ptr += 2 * (len + 1);
2140 ses->serverDomain[2*len] = 0;
2141 ses->serverDomain[1+(2*len)] = 0;
2142 } /* else no more room so create dummy domain string */
2143 else
Steve French433dc242005-04-28 22:41:08 -07002144 ses->serverDomain =
2145 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002147 /* if these kcallocs fail not much we
2148 can do, but better to not fail the
2149 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002151 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002153 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 }
2155 } else { /* ASCII */
2156 len = strnlen(bcc_ptr, 1024);
2157 if (((long) bcc_ptr + len) - (long)
2158 pByteArea(smb_buffer_response)
2159 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002160 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2161 if(ses->serverOS == NULL)
2162 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 strncpy(ses->serverOS,bcc_ptr, len);
2164
2165 bcc_ptr += len;
2166 bcc_ptr[0] = 0; /* null terminate the string */
2167 bcc_ptr++;
2168
2169 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002170 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2171 if(ses->serverNOS == NULL)
2172 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 strncpy(ses->serverNOS, bcc_ptr, len);
2174 bcc_ptr += len;
2175 bcc_ptr[0] = 0;
2176 bcc_ptr++;
2177
2178 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002179 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2180 if(ses->serverDomain == NULL)
2181 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 strncpy(ses->serverDomain, bcc_ptr, len);
2183 bcc_ptr += len;
2184 bcc_ptr[0] = 0;
2185 bcc_ptr++;
2186 } else
2187 cFYI(1,
2188 ("Variable field of length %d extends beyond end of smb ",
2189 len));
2190 }
2191 } else {
2192 cERROR(1,
2193 (" Security Blob Length extends beyond end of SMB"));
2194 }
2195 } else {
2196 cERROR(1,
2197 (" Invalid Word count %d: ",
2198 smb_buffer_response->WordCount));
2199 rc = -EIO;
2200 }
Steve French433dc242005-04-28 22:41:08 -07002201sesssetup_nomem: /* do not return an error on nomem for the info strings,
2202 since that could make reconnection harder, and
2203 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 if (smb_buffer)
2205 cifs_buf_release(smb_buffer);
2206
2207 return rc;
2208}
2209
2210static int
2211CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2212 char *SecurityBlob,int SecurityBlobLength,
2213 const struct nls_table *nls_codepage)
2214{
2215 struct smb_hdr *smb_buffer;
2216 struct smb_hdr *smb_buffer_response;
2217 SESSION_SETUP_ANDX *pSMB;
2218 SESSION_SETUP_ANDX *pSMBr;
2219 char *bcc_ptr;
2220 char *user;
2221 char *domain;
2222 int rc = 0;
2223 int remaining_words = 0;
2224 int bytes_returned = 0;
2225 int len;
2226 __u32 capabilities;
2227 __u16 count;
2228
2229 cFYI(1, ("In spnego sesssetup "));
2230 if(ses == NULL)
2231 return -EINVAL;
2232 user = ses->userName;
2233 domain = ses->domainName;
2234
2235 smb_buffer = cifs_buf_get();
2236 if (smb_buffer == NULL) {
2237 return -ENOMEM;
2238 }
2239 smb_buffer_response = smb_buffer;
2240 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2241
2242 /* send SMBsessionSetup here */
2243 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2244 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002245
2246 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2248 pSMB->req.AndXCommand = 0xFF;
2249 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2250 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2251
2252 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2253 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2254
2255 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2256 CAP_EXTENDED_SECURITY;
2257 if (ses->capabilities & CAP_UNICODE) {
2258 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2259 capabilities |= CAP_UNICODE;
2260 }
2261 if (ses->capabilities & CAP_STATUS32) {
2262 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2263 capabilities |= CAP_STATUS32;
2264 }
2265 if (ses->capabilities & CAP_DFS) {
2266 smb_buffer->Flags2 |= SMBFLG2_DFS;
2267 capabilities |= CAP_DFS;
2268 }
2269 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2270
2271 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2272 bcc_ptr = pByteArea(smb_buffer);
2273 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2274 bcc_ptr += SecurityBlobLength;
2275
2276 if (ses->capabilities & CAP_UNICODE) {
2277 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2278 *bcc_ptr = 0;
2279 bcc_ptr++;
2280 }
2281 bytes_returned =
2282 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2283 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2284 bcc_ptr += 2; /* trailing null */
2285 if (domain == NULL)
2286 bytes_returned =
2287 cifs_strtoUCS((wchar_t *) bcc_ptr,
2288 "CIFS_LINUX_DOM", 32, nls_codepage);
2289 else
2290 bytes_returned =
2291 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2292 nls_codepage);
2293 bcc_ptr += 2 * bytes_returned;
2294 bcc_ptr += 2;
2295 bytes_returned =
2296 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2297 32, nls_codepage);
2298 bcc_ptr += 2 * bytes_returned;
2299 bytes_returned =
2300 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2301 nls_codepage);
2302 bcc_ptr += 2 * bytes_returned;
2303 bcc_ptr += 2;
2304 bytes_returned =
2305 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2306 64, nls_codepage);
2307 bcc_ptr += 2 * bytes_returned;
2308 bcc_ptr += 2;
2309 } else {
2310 strncpy(bcc_ptr, user, 200);
2311 bcc_ptr += strnlen(user, 200);
2312 *bcc_ptr = 0;
2313 bcc_ptr++;
2314 if (domain == NULL) {
2315 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2316 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2317 } else {
2318 strncpy(bcc_ptr, domain, 64);
2319 bcc_ptr += strnlen(domain, 64);
2320 *bcc_ptr = 0;
2321 bcc_ptr++;
2322 }
2323 strcpy(bcc_ptr, "Linux version ");
2324 bcc_ptr += strlen("Linux version ");
2325 strcpy(bcc_ptr, system_utsname.release);
2326 bcc_ptr += strlen(system_utsname.release) + 1;
2327 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2328 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2329 }
2330 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2331 smb_buffer->smb_buf_length += count;
2332 pSMB->req.ByteCount = cpu_to_le16(count);
2333
2334 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2335 &bytes_returned, 1);
2336 if (rc) {
2337/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2338 } else if ((smb_buffer_response->WordCount == 3)
2339 || (smb_buffer_response->WordCount == 4)) {
2340 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2341 __u16 blob_len =
2342 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2343 if (action & GUEST_LOGIN)
2344 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2345 if (ses) {
2346 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2347 cFYI(1, ("UID = %d ", ses->Suid));
2348 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2349
2350 /* BB Fix below to make endian neutral !! */
2351
2352 if ((pSMBr->resp.hdr.WordCount == 3)
2353 || ((pSMBr->resp.hdr.WordCount == 4)
2354 && (blob_len <
2355 pSMBr->resp.ByteCount))) {
2356 if (pSMBr->resp.hdr.WordCount == 4) {
2357 bcc_ptr +=
2358 blob_len;
2359 cFYI(1,
2360 ("Security Blob Length %d ",
2361 blob_len));
2362 }
2363
2364 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2365 if ((long) (bcc_ptr) % 2) {
2366 remaining_words =
2367 (BCC(smb_buffer_response)
2368 - 1) / 2;
2369 bcc_ptr++; /* Unicode strings must be word aligned */
2370 } else {
2371 remaining_words =
2372 BCC
2373 (smb_buffer_response) / 2;
2374 }
2375 len =
2376 UniStrnlen((wchar_t *) bcc_ptr,
2377 remaining_words - 1);
2378/* We look for obvious messed up bcc or strings in response so we do not go off
2379 the end since (at least) WIN2K and Windows XP have a major bug in not null
2380 terminating last Unicode string in response */
2381 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002382 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 cifs_strfromUCS_le(ses->serverOS,
2384 (wchar_t *)
2385 bcc_ptr, len,
2386 nls_codepage);
2387 bcc_ptr += 2 * (len + 1);
2388 remaining_words -= len + 1;
2389 ses->serverOS[2 * len] = 0;
2390 ses->serverOS[1 + (2 * len)] = 0;
2391 if (remaining_words > 0) {
2392 len = UniStrnlen((wchar_t *)bcc_ptr,
2393 remaining_words
2394 - 1);
2395 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002396 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 GFP_KERNEL);
2398 cifs_strfromUCS_le(ses->serverNOS,
2399 (wchar_t *)bcc_ptr,
2400 len,
2401 nls_codepage);
2402 bcc_ptr += 2 * (len + 1);
2403 ses->serverNOS[2 * len] = 0;
2404 ses->serverNOS[1 + (2 * len)] = 0;
2405 remaining_words -= len + 1;
2406 if (remaining_words > 0) {
2407 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2408 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002409 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 cifs_strfromUCS_le(ses->serverDomain,
2411 (wchar_t *)bcc_ptr,
2412 len,
2413 nls_codepage);
2414 bcc_ptr += 2*(len+1);
2415 ses->serverDomain[2*len] = 0;
2416 ses->serverDomain[1+(2*len)] = 0;
2417 } /* else no more room so create dummy domain string */
2418 else
2419 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002420 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002422 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2423 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 }
2425 } else { /* ASCII */
2426
2427 len = strnlen(bcc_ptr, 1024);
2428 if (((long) bcc_ptr + len) - (long)
2429 pByteArea(smb_buffer_response)
2430 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002431 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 strncpy(ses->serverOS, bcc_ptr, len);
2433
2434 bcc_ptr += len;
2435 bcc_ptr[0] = 0; /* null terminate the string */
2436 bcc_ptr++;
2437
2438 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002439 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 strncpy(ses->serverNOS, bcc_ptr, len);
2441 bcc_ptr += len;
2442 bcc_ptr[0] = 0;
2443 bcc_ptr++;
2444
2445 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002446 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 strncpy(ses->serverDomain, bcc_ptr, len);
2448 bcc_ptr += len;
2449 bcc_ptr[0] = 0;
2450 bcc_ptr++;
2451 } else
2452 cFYI(1,
2453 ("Variable field of length %d extends beyond end of smb ",
2454 len));
2455 }
2456 } else {
2457 cERROR(1,
2458 (" Security Blob Length extends beyond end of SMB"));
2459 }
2460 } else {
2461 cERROR(1, ("No session structure passed in."));
2462 }
2463 } else {
2464 cERROR(1,
2465 (" Invalid Word count %d: ",
2466 smb_buffer_response->WordCount));
2467 rc = -EIO;
2468 }
2469
2470 if (smb_buffer)
2471 cifs_buf_release(smb_buffer);
2472
2473 return rc;
2474}
2475
2476static int
2477CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2478 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2479 const struct nls_table *nls_codepage)
2480{
2481 struct smb_hdr *smb_buffer;
2482 struct smb_hdr *smb_buffer_response;
2483 SESSION_SETUP_ANDX *pSMB;
2484 SESSION_SETUP_ANDX *pSMBr;
2485 char *bcc_ptr;
2486 char *domain;
2487 int rc = 0;
2488 int remaining_words = 0;
2489 int bytes_returned = 0;
2490 int len;
2491 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2492 PNEGOTIATE_MESSAGE SecurityBlob;
2493 PCHALLENGE_MESSAGE SecurityBlob2;
2494 __u32 negotiate_flags, capabilities;
2495 __u16 count;
2496
2497 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2498 if(ses == NULL)
2499 return -EINVAL;
2500 domain = ses->domainName;
2501 *pNTLMv2_flag = FALSE;
2502 smb_buffer = cifs_buf_get();
2503 if (smb_buffer == NULL) {
2504 return -ENOMEM;
2505 }
2506 smb_buffer_response = smb_buffer;
2507 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2508 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2509
2510 /* send SMBsessionSetup here */
2511 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2512 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002513
2514 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2516 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2517
2518 pSMB->req.AndXCommand = 0xFF;
2519 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2520 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2521
2522 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2523 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2524
2525 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2526 CAP_EXTENDED_SECURITY;
2527 if (ses->capabilities & CAP_UNICODE) {
2528 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2529 capabilities |= CAP_UNICODE;
2530 }
2531 if (ses->capabilities & CAP_STATUS32) {
2532 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2533 capabilities |= CAP_STATUS32;
2534 }
2535 if (ses->capabilities & CAP_DFS) {
2536 smb_buffer->Flags2 |= SMBFLG2_DFS;
2537 capabilities |= CAP_DFS;
2538 }
2539 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2540
2541 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2542 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2543 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2544 SecurityBlob->MessageType = NtLmNegotiate;
2545 negotiate_flags =
2546 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2547 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2548 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2549 if(sign_CIFS_PDUs)
2550 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2551 if(ntlmv2_support)
2552 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2553 /* setup pointers to domain name and workstation name */
2554 bcc_ptr += SecurityBlobLength;
2555
2556 SecurityBlob->WorkstationName.Buffer = 0;
2557 SecurityBlob->WorkstationName.Length = 0;
2558 SecurityBlob->WorkstationName.MaximumLength = 0;
2559
2560 if (domain == NULL) {
2561 SecurityBlob->DomainName.Buffer = 0;
2562 SecurityBlob->DomainName.Length = 0;
2563 SecurityBlob->DomainName.MaximumLength = 0;
2564 } else {
2565 __u16 len;
2566 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2567 strncpy(bcc_ptr, domain, 63);
2568 len = strnlen(domain, 64);
2569 SecurityBlob->DomainName.MaximumLength =
2570 cpu_to_le16(len);
2571 SecurityBlob->DomainName.Buffer =
2572 cpu_to_le32((long) &SecurityBlob->
2573 DomainString -
2574 (long) &SecurityBlob->Signature);
2575 bcc_ptr += len;
2576 SecurityBlobLength += len;
2577 SecurityBlob->DomainName.Length =
2578 cpu_to_le16(len);
2579 }
2580 if (ses->capabilities & CAP_UNICODE) {
2581 if ((long) bcc_ptr % 2) {
2582 *bcc_ptr = 0;
2583 bcc_ptr++;
2584 }
2585
2586 bytes_returned =
2587 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2588 32, nls_codepage);
2589 bcc_ptr += 2 * bytes_returned;
2590 bytes_returned =
2591 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2592 nls_codepage);
2593 bcc_ptr += 2 * bytes_returned;
2594 bcc_ptr += 2; /* null terminate Linux version */
2595 bytes_returned =
2596 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2597 64, nls_codepage);
2598 bcc_ptr += 2 * bytes_returned;
2599 *(bcc_ptr + 1) = 0;
2600 *(bcc_ptr + 2) = 0;
2601 bcc_ptr += 2; /* null terminate network opsys string */
2602 *(bcc_ptr + 1) = 0;
2603 *(bcc_ptr + 2) = 0;
2604 bcc_ptr += 2; /* null domain */
2605 } else { /* ASCII */
2606 strcpy(bcc_ptr, "Linux version ");
2607 bcc_ptr += strlen("Linux version ");
2608 strcpy(bcc_ptr, system_utsname.release);
2609 bcc_ptr += strlen(system_utsname.release) + 1;
2610 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2611 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2612 bcc_ptr++; /* empty domain field */
2613 *bcc_ptr = 0;
2614 }
2615 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2616 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2617 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2618 smb_buffer->smb_buf_length += count;
2619 pSMB->req.ByteCount = cpu_to_le16(count);
2620
2621 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2622 &bytes_returned, 1);
2623
2624 if (smb_buffer_response->Status.CifsError ==
2625 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2626 rc = 0;
2627
2628 if (rc) {
2629/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2630 } else if ((smb_buffer_response->WordCount == 3)
2631 || (smb_buffer_response->WordCount == 4)) {
2632 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2633 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2634
2635 if (action & GUEST_LOGIN)
2636 cFYI(1, (" Guest login"));
2637 /* Do we want to set anything in SesInfo struct when guest login? */
2638
2639 bcc_ptr = pByteArea(smb_buffer_response);
2640 /* response can have either 3 or 4 word count - Samba sends 3 */
2641
2642 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2643 if (SecurityBlob2->MessageType != NtLmChallenge) {
2644 cFYI(1,
2645 ("Unexpected NTLMSSP message type received %d",
2646 SecurityBlob2->MessageType));
2647 } else if (ses) {
2648 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2649 cFYI(1, ("UID = %d ", ses->Suid));
2650 if ((pSMBr->resp.hdr.WordCount == 3)
2651 || ((pSMBr->resp.hdr.WordCount == 4)
2652 && (blob_len <
2653 pSMBr->resp.ByteCount))) {
2654
2655 if (pSMBr->resp.hdr.WordCount == 4) {
2656 bcc_ptr += blob_len;
2657 cFYI(1,
2658 ("Security Blob Length %d ",
2659 blob_len));
2660 }
2661
2662 cFYI(1, ("NTLMSSP Challenge rcvd "));
2663
2664 memcpy(ses->server->cryptKey,
2665 SecurityBlob2->Challenge,
2666 CIFS_CRYPTO_KEY_SIZE);
2667 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2668 *pNTLMv2_flag = TRUE;
2669
2670 if((SecurityBlob2->NegotiateFlags &
2671 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2672 || (sign_CIFS_PDUs > 1))
2673 ses->server->secMode |=
2674 SECMODE_SIGN_REQUIRED;
2675 if ((SecurityBlob2->NegotiateFlags &
2676 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2677 ses->server->secMode |=
2678 SECMODE_SIGN_ENABLED;
2679
2680 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2681 if ((long) (bcc_ptr) % 2) {
2682 remaining_words =
2683 (BCC(smb_buffer_response)
2684 - 1) / 2;
2685 bcc_ptr++; /* Unicode strings must be word aligned */
2686 } else {
2687 remaining_words =
2688 BCC
2689 (smb_buffer_response) / 2;
2690 }
2691 len =
2692 UniStrnlen((wchar_t *) bcc_ptr,
2693 remaining_words - 1);
2694/* We look for obvious messed up bcc or strings in response so we do not go off
2695 the end since (at least) WIN2K and Windows XP have a major bug in not null
2696 terminating last Unicode string in response */
2697 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002698 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 cifs_strfromUCS_le(ses->serverOS,
2700 (wchar_t *)
2701 bcc_ptr, len,
2702 nls_codepage);
2703 bcc_ptr += 2 * (len + 1);
2704 remaining_words -= len + 1;
2705 ses->serverOS[2 * len] = 0;
2706 ses->serverOS[1 + (2 * len)] = 0;
2707 if (remaining_words > 0) {
2708 len = UniStrnlen((wchar_t *)
2709 bcc_ptr,
2710 remaining_words
2711 - 1);
2712 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002713 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 GFP_KERNEL);
2715 cifs_strfromUCS_le(ses->
2716 serverNOS,
2717 (wchar_t *)
2718 bcc_ptr,
2719 len,
2720 nls_codepage);
2721 bcc_ptr += 2 * (len + 1);
2722 ses->serverNOS[2 * len] = 0;
2723 ses->serverNOS[1 +
2724 (2 * len)] = 0;
2725 remaining_words -= len + 1;
2726 if (remaining_words > 0) {
2727 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2728 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2729 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002730 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 (len +
2732 1),
2733 GFP_KERNEL);
2734 cifs_strfromUCS_le
2735 (ses->
2736 serverDomain,
2737 (wchar_t *)
2738 bcc_ptr, len,
2739 nls_codepage);
2740 bcc_ptr +=
2741 2 * (len + 1);
2742 ses->
2743 serverDomain[2
2744 * len]
2745 = 0;
2746 ses->
2747 serverDomain[1
2748 +
2749 (2
2750 *
2751 len)]
2752 = 0;
2753 } /* else no more room so create dummy domain string */
2754 else
2755 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002756 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 GFP_KERNEL);
2758 } else { /* no room so create dummy domain and NOS string */
2759 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002760 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002762 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 }
2764 } else { /* ASCII */
2765 len = strnlen(bcc_ptr, 1024);
2766 if (((long) bcc_ptr + len) - (long)
2767 pByteArea(smb_buffer_response)
2768 <= BCC(smb_buffer_response)) {
2769 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002770 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 GFP_KERNEL);
2772 strncpy(ses->serverOS,
2773 bcc_ptr, len);
2774
2775 bcc_ptr += len;
2776 bcc_ptr[0] = 0; /* null terminate string */
2777 bcc_ptr++;
2778
2779 len = strnlen(bcc_ptr, 1024);
2780 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002781 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 GFP_KERNEL);
2783 strncpy(ses->serverNOS, bcc_ptr, len);
2784 bcc_ptr += len;
2785 bcc_ptr[0] = 0;
2786 bcc_ptr++;
2787
2788 len = strnlen(bcc_ptr, 1024);
2789 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002790 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 GFP_KERNEL);
2792 strncpy(ses->serverDomain, bcc_ptr, len);
2793 bcc_ptr += len;
2794 bcc_ptr[0] = 0;
2795 bcc_ptr++;
2796 } else
2797 cFYI(1,
2798 ("Variable field of length %d extends beyond end of smb ",
2799 len));
2800 }
2801 } else {
2802 cERROR(1,
2803 (" Security Blob Length extends beyond end of SMB"));
2804 }
2805 } else {
2806 cERROR(1, ("No session structure passed in."));
2807 }
2808 } else {
2809 cERROR(1,
2810 (" Invalid Word count %d: ",
2811 smb_buffer_response->WordCount));
2812 rc = -EIO;
2813 }
2814
2815 if (smb_buffer)
2816 cifs_buf_release(smb_buffer);
2817
2818 return rc;
2819}
2820static int
2821CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2822 char *ntlm_session_key, int ntlmv2_flag,
2823 const struct nls_table *nls_codepage)
2824{
2825 struct smb_hdr *smb_buffer;
2826 struct smb_hdr *smb_buffer_response;
2827 SESSION_SETUP_ANDX *pSMB;
2828 SESSION_SETUP_ANDX *pSMBr;
2829 char *bcc_ptr;
2830 char *user;
2831 char *domain;
2832 int rc = 0;
2833 int remaining_words = 0;
2834 int bytes_returned = 0;
2835 int len;
2836 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2837 PAUTHENTICATE_MESSAGE SecurityBlob;
2838 __u32 negotiate_flags, capabilities;
2839 __u16 count;
2840
2841 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2842 if(ses == NULL)
2843 return -EINVAL;
2844 user = ses->userName;
2845 domain = ses->domainName;
2846 smb_buffer = cifs_buf_get();
2847 if (smb_buffer == NULL) {
2848 return -ENOMEM;
2849 }
2850 smb_buffer_response = smb_buffer;
2851 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2852 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2853
2854 /* send SMBsessionSetup here */
2855 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2856 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002857
2858 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2860 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2861 pSMB->req.AndXCommand = 0xFF;
2862 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2863 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2864
2865 pSMB->req.hdr.Uid = ses->Suid;
2866
2867 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2868 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2869
2870 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2871 CAP_EXTENDED_SECURITY;
2872 if (ses->capabilities & CAP_UNICODE) {
2873 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2874 capabilities |= CAP_UNICODE;
2875 }
2876 if (ses->capabilities & CAP_STATUS32) {
2877 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2878 capabilities |= CAP_STATUS32;
2879 }
2880 if (ses->capabilities & CAP_DFS) {
2881 smb_buffer->Flags2 |= SMBFLG2_DFS;
2882 capabilities |= CAP_DFS;
2883 }
2884 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2885
2886 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2887 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2888 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2889 SecurityBlob->MessageType = NtLmAuthenticate;
2890 bcc_ptr += SecurityBlobLength;
2891 negotiate_flags =
2892 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2893 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2894 0x80000000 | NTLMSSP_NEGOTIATE_128;
2895 if(sign_CIFS_PDUs)
2896 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2897 if(ntlmv2_flag)
2898 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2899
2900/* setup pointers to domain name and workstation name */
2901
2902 SecurityBlob->WorkstationName.Buffer = 0;
2903 SecurityBlob->WorkstationName.Length = 0;
2904 SecurityBlob->WorkstationName.MaximumLength = 0;
2905 SecurityBlob->SessionKey.Length = 0;
2906 SecurityBlob->SessionKey.MaximumLength = 0;
2907 SecurityBlob->SessionKey.Buffer = 0;
2908
2909 SecurityBlob->LmChallengeResponse.Length = 0;
2910 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2911 SecurityBlob->LmChallengeResponse.Buffer = 0;
2912
2913 SecurityBlob->NtChallengeResponse.Length =
2914 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2915 SecurityBlob->NtChallengeResponse.MaximumLength =
2916 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2917 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2918 SecurityBlob->NtChallengeResponse.Buffer =
2919 cpu_to_le32(SecurityBlobLength);
2920 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2921 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2922
2923 if (ses->capabilities & CAP_UNICODE) {
2924 if (domain == NULL) {
2925 SecurityBlob->DomainName.Buffer = 0;
2926 SecurityBlob->DomainName.Length = 0;
2927 SecurityBlob->DomainName.MaximumLength = 0;
2928 } else {
2929 __u16 len =
2930 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2931 nls_codepage);
2932 len *= 2;
2933 SecurityBlob->DomainName.MaximumLength =
2934 cpu_to_le16(len);
2935 SecurityBlob->DomainName.Buffer =
2936 cpu_to_le32(SecurityBlobLength);
2937 bcc_ptr += len;
2938 SecurityBlobLength += len;
2939 SecurityBlob->DomainName.Length =
2940 cpu_to_le16(len);
2941 }
2942 if (user == NULL) {
2943 SecurityBlob->UserName.Buffer = 0;
2944 SecurityBlob->UserName.Length = 0;
2945 SecurityBlob->UserName.MaximumLength = 0;
2946 } else {
2947 __u16 len =
2948 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2949 nls_codepage);
2950 len *= 2;
2951 SecurityBlob->UserName.MaximumLength =
2952 cpu_to_le16(len);
2953 SecurityBlob->UserName.Buffer =
2954 cpu_to_le32(SecurityBlobLength);
2955 bcc_ptr += len;
2956 SecurityBlobLength += len;
2957 SecurityBlob->UserName.Length =
2958 cpu_to_le16(len);
2959 }
2960
2961 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2962 SecurityBlob->WorkstationName.Length *= 2;
2963 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2964 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2965 bcc_ptr += SecurityBlob->WorkstationName.Length;
2966 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2967 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2968
2969 if ((long) bcc_ptr % 2) {
2970 *bcc_ptr = 0;
2971 bcc_ptr++;
2972 }
2973 bytes_returned =
2974 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2975 32, nls_codepage);
2976 bcc_ptr += 2 * bytes_returned;
2977 bytes_returned =
2978 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2979 nls_codepage);
2980 bcc_ptr += 2 * bytes_returned;
2981 bcc_ptr += 2; /* null term version string */
2982 bytes_returned =
2983 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2984 64, nls_codepage);
2985 bcc_ptr += 2 * bytes_returned;
2986 *(bcc_ptr + 1) = 0;
2987 *(bcc_ptr + 2) = 0;
2988 bcc_ptr += 2; /* null terminate network opsys string */
2989 *(bcc_ptr + 1) = 0;
2990 *(bcc_ptr + 2) = 0;
2991 bcc_ptr += 2; /* null domain */
2992 } else { /* ASCII */
2993 if (domain == NULL) {
2994 SecurityBlob->DomainName.Buffer = 0;
2995 SecurityBlob->DomainName.Length = 0;
2996 SecurityBlob->DomainName.MaximumLength = 0;
2997 } else {
2998 __u16 len;
2999 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3000 strncpy(bcc_ptr, domain, 63);
3001 len = strnlen(domain, 64);
3002 SecurityBlob->DomainName.MaximumLength =
3003 cpu_to_le16(len);
3004 SecurityBlob->DomainName.Buffer =
3005 cpu_to_le32(SecurityBlobLength);
3006 bcc_ptr += len;
3007 SecurityBlobLength += len;
3008 SecurityBlob->DomainName.Length = cpu_to_le16(len);
3009 }
3010 if (user == NULL) {
3011 SecurityBlob->UserName.Buffer = 0;
3012 SecurityBlob->UserName.Length = 0;
3013 SecurityBlob->UserName.MaximumLength = 0;
3014 } else {
3015 __u16 len;
3016 strncpy(bcc_ptr, user, 63);
3017 len = strnlen(user, 64);
3018 SecurityBlob->UserName.MaximumLength =
3019 cpu_to_le16(len);
3020 SecurityBlob->UserName.Buffer =
3021 cpu_to_le32(SecurityBlobLength);
3022 bcc_ptr += len;
3023 SecurityBlobLength += len;
3024 SecurityBlob->UserName.Length = cpu_to_le16(len);
3025 }
3026 /* BB fill in our workstation name if known BB */
3027
3028 strcpy(bcc_ptr, "Linux version ");
3029 bcc_ptr += strlen("Linux version ");
3030 strcpy(bcc_ptr, system_utsname.release);
3031 bcc_ptr += strlen(system_utsname.release) + 1;
3032 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3033 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3034 bcc_ptr++; /* null domain */
3035 *bcc_ptr = 0;
3036 }
3037 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3038 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3039 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3040 smb_buffer->smb_buf_length += count;
3041 pSMB->req.ByteCount = cpu_to_le16(count);
3042
3043 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3044 &bytes_returned, 1);
3045 if (rc) {
3046/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3047 } else if ((smb_buffer_response->WordCount == 3)
3048 || (smb_buffer_response->WordCount == 4)) {
3049 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3050 __u16 blob_len =
3051 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3052 if (action & GUEST_LOGIN)
3053 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3054/* if(SecurityBlob2->MessageType != NtLm??){
3055 cFYI("Unexpected message type on auth response is %d "));
3056 } */
3057 if (ses) {
3058 cFYI(1,
3059 ("Does UID on challenge %d match auth response UID %d ",
3060 ses->Suid, smb_buffer_response->Uid));
3061 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3062 bcc_ptr = pByteArea(smb_buffer_response);
3063 /* response can have either 3 or 4 word count - Samba sends 3 */
3064 if ((pSMBr->resp.hdr.WordCount == 3)
3065 || ((pSMBr->resp.hdr.WordCount == 4)
3066 && (blob_len <
3067 pSMBr->resp.ByteCount))) {
3068 if (pSMBr->resp.hdr.WordCount == 4) {
3069 bcc_ptr +=
3070 blob_len;
3071 cFYI(1,
3072 ("Security Blob Length %d ",
3073 blob_len));
3074 }
3075
3076 cFYI(1,
3077 ("NTLMSSP response to Authenticate "));
3078
3079 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3080 if ((long) (bcc_ptr) % 2) {
3081 remaining_words =
3082 (BCC(smb_buffer_response)
3083 - 1) / 2;
3084 bcc_ptr++; /* Unicode strings must be word aligned */
3085 } else {
3086 remaining_words = BCC(smb_buffer_response) / 2;
3087 }
3088 len =
3089 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3090/* We look for obvious messed up bcc or strings in response so we do not go off
3091 the end since (at least) WIN2K and Windows XP have a major bug in not null
3092 terminating last Unicode string in response */
3093 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07003094 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 cifs_strfromUCS_le(ses->serverOS,
3096 (wchar_t *)
3097 bcc_ptr, len,
3098 nls_codepage);
3099 bcc_ptr += 2 * (len + 1);
3100 remaining_words -= len + 1;
3101 ses->serverOS[2 * len] = 0;
3102 ses->serverOS[1 + (2 * len)] = 0;
3103 if (remaining_words > 0) {
3104 len = UniStrnlen((wchar_t *)
3105 bcc_ptr,
3106 remaining_words
3107 - 1);
3108 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07003109 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 GFP_KERNEL);
3111 cifs_strfromUCS_le(ses->
3112 serverNOS,
3113 (wchar_t *)
3114 bcc_ptr,
3115 len,
3116 nls_codepage);
3117 bcc_ptr += 2 * (len + 1);
3118 ses->serverNOS[2 * len] = 0;
3119 ses->serverNOS[1+(2*len)] = 0;
3120 remaining_words -= len + 1;
3121 if (remaining_words > 0) {
3122 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3123 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3124 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07003125 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 (len +
3127 1),
3128 GFP_KERNEL);
3129 cifs_strfromUCS_le
3130 (ses->
3131 serverDomain,
3132 (wchar_t *)
3133 bcc_ptr, len,
3134 nls_codepage);
3135 bcc_ptr +=
3136 2 * (len + 1);
3137 ses->
3138 serverDomain[2
3139 * len]
3140 = 0;
3141 ses->
3142 serverDomain[1
3143 +
3144 (2
3145 *
3146 len)]
3147 = 0;
3148 } /* else no more room so create dummy domain string */
3149 else
Steve French433dc242005-04-28 22:41:08 -07003150 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07003152 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3153 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 }
3155 } else { /* ASCII */
3156 len = strnlen(bcc_ptr, 1024);
3157 if (((long) bcc_ptr + len) -
3158 (long) pByteArea(smb_buffer_response)
3159 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07003160 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 strncpy(ses->serverOS,bcc_ptr, len);
3162
3163 bcc_ptr += len;
3164 bcc_ptr[0] = 0; /* null terminate the string */
3165 bcc_ptr++;
3166
3167 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003168 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 strncpy(ses->serverNOS, bcc_ptr, len);
3170 bcc_ptr += len;
3171 bcc_ptr[0] = 0;
3172 bcc_ptr++;
3173
3174 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003175 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 strncpy(ses->serverDomain, bcc_ptr, len);
3177 bcc_ptr += len;
3178 bcc_ptr[0] = 0;
3179 bcc_ptr++;
3180 } else
3181 cFYI(1,
3182 ("Variable field of length %d extends beyond end of smb ",
3183 len));
3184 }
3185 } else {
3186 cERROR(1,
3187 (" Security Blob Length extends beyond end of SMB"));
3188 }
3189 } else {
3190 cERROR(1, ("No session structure passed in."));
3191 }
3192 } else {
3193 cERROR(1,
3194 (" Invalid Word count %d: ",
3195 smb_buffer_response->WordCount));
3196 rc = -EIO;
3197 }
3198
3199 if (smb_buffer)
3200 cifs_buf_release(smb_buffer);
3201
3202 return rc;
3203}
3204
3205int
3206CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3207 const char *tree, struct cifsTconInfo *tcon,
3208 const struct nls_table *nls_codepage)
3209{
3210 struct smb_hdr *smb_buffer;
3211 struct smb_hdr *smb_buffer_response;
3212 TCONX_REQ *pSMB;
3213 TCONX_RSP *pSMBr;
3214 unsigned char *bcc_ptr;
3215 int rc = 0;
3216 int length;
3217 __u16 count;
3218
3219 if (ses == NULL)
3220 return -EIO;
3221
3222 smb_buffer = cifs_buf_get();
3223 if (smb_buffer == NULL) {
3224 return -ENOMEM;
3225 }
3226 smb_buffer_response = smb_buffer;
3227
3228 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3229 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003230
3231 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 smb_buffer->Uid = ses->Suid;
3233 pSMB = (TCONX_REQ *) smb_buffer;
3234 pSMBr = (TCONX_RSP *) smb_buffer_response;
3235
3236 pSMB->AndXCommand = 0xFF;
3237 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3238 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3239 bcc_ptr = &pSMB->Password[0];
3240 bcc_ptr++; /* skip password */
3241
3242 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3243 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3244
3245 if (ses->capabilities & CAP_STATUS32) {
3246 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3247 }
3248 if (ses->capabilities & CAP_DFS) {
3249 smb_buffer->Flags2 |= SMBFLG2_DFS;
3250 }
3251 if (ses->capabilities & CAP_UNICODE) {
3252 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3253 length =
3254 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3255 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3256 bcc_ptr += 2; /* skip trailing null */
3257 } else { /* ASCII */
3258
3259 strcpy(bcc_ptr, tree);
3260 bcc_ptr += strlen(tree) + 1;
3261 }
3262 strcpy(bcc_ptr, "?????");
3263 bcc_ptr += strlen("?????");
3264 bcc_ptr += 1;
3265 count = bcc_ptr - &pSMB->Password[0];
3266 pSMB->hdr.smb_buf_length += count;
3267 pSMB->ByteCount = cpu_to_le16(count);
3268
3269 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3270
3271 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3272 /* above now done in SendReceive */
3273 if ((rc == 0) && (tcon != NULL)) {
3274 tcon->tidStatus = CifsGood;
3275 tcon->tid = smb_buffer_response->Tid;
3276 bcc_ptr = pByteArea(smb_buffer_response);
3277 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3278 /* skip service field (NB: this field is always ASCII) */
3279 bcc_ptr += length + 1;
3280 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3281 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3282 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3283 if ((bcc_ptr + (2 * length)) -
3284 pByteArea(smb_buffer_response) <=
3285 BCC(smb_buffer_response)) {
3286 if(tcon->nativeFileSystem)
3287 kfree(tcon->nativeFileSystem);
3288 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003289 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 cifs_strfromUCS_le(tcon->nativeFileSystem,
3291 (wchar_t *) bcc_ptr,
3292 length, nls_codepage);
3293 bcc_ptr += 2 * length;
3294 bcc_ptr[0] = 0; /* null terminate the string */
3295 bcc_ptr[1] = 0;
3296 bcc_ptr += 2;
3297 }
3298 /* else do not bother copying these informational fields */
3299 } else {
3300 length = strnlen(bcc_ptr, 1024);
3301 if ((bcc_ptr + length) -
3302 pByteArea(smb_buffer_response) <=
3303 BCC(smb_buffer_response)) {
3304 if(tcon->nativeFileSystem)
3305 kfree(tcon->nativeFileSystem);
3306 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003307 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 strncpy(tcon->nativeFileSystem, bcc_ptr,
3309 length);
3310 }
3311 /* else do not bother copying these informational fields */
3312 }
3313 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3314 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3315 } else if ((rc == 0) && tcon == NULL) {
3316 /* all we need to save for IPC$ connection */
3317 ses->ipc_tid = smb_buffer_response->Tid;
3318 }
3319
3320 if (smb_buffer)
3321 cifs_buf_release(smb_buffer);
3322 return rc;
3323}
3324
3325int
3326cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3327{
3328 int rc = 0;
3329 int xid;
3330 struct cifsSesInfo *ses = NULL;
3331 struct task_struct *cifsd_task;
3332
3333 xid = GetXid();
3334
3335 if (cifs_sb->tcon) {
3336 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3337 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3338 if (rc == -EBUSY) {
3339 FreeXid(xid);
3340 return 0;
3341 }
3342 tconInfoFree(cifs_sb->tcon);
3343 if ((ses) && (ses->server)) {
3344 /* save off task so we do not refer to ses later */
3345 cifsd_task = ses->server->tsk;
3346 cFYI(1, ("About to do SMBLogoff "));
3347 rc = CIFSSMBLogoff(xid, ses);
3348 if (rc == -EBUSY) {
3349 FreeXid(xid);
3350 return 0;
3351 } else if (rc == -ESHUTDOWN) {
3352 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003353 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003355 wait_for_completion(&cifsd_complete);
3356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 rc = 0;
3358 } /* else - we have an smb session
3359 left on this socket do not kill cifsd */
3360 } else
3361 cFYI(1, ("No session or bad tcon"));
3362 }
3363
3364 cifs_sb->tcon = NULL;
3365 if (ses) {
3366 set_current_state(TASK_INTERRUPTIBLE);
3367 schedule_timeout(HZ / 2);
3368 }
3369 if (ses)
3370 sesInfoFree(ses);
3371
3372 FreeXid(xid);
3373 return rc; /* BB check if we should always return zero here */
3374}
3375
3376int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3377 struct nls_table * nls_info)
3378{
3379 int rc = 0;
3380 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3381 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003382 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383
3384 /* what if server changes its buffer size after dropping the session? */
3385 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3386 rc = CIFSSMBNegotiate(xid, pSesInfo);
3387 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3388 rc = CIFSSMBNegotiate(xid, pSesInfo);
3389 if(rc == -EAGAIN)
3390 rc = -EHOSTDOWN;
3391 }
3392 if(rc == 0) {
3393 spin_lock(&GlobalMid_Lock);
3394 if(pSesInfo->server->tcpStatus != CifsExiting)
3395 pSesInfo->server->tcpStatus = CifsGood;
3396 else
3397 rc = -EHOSTDOWN;
3398 spin_unlock(&GlobalMid_Lock);
3399
3400 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003401 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 }
3403 if (!rc) {
3404 pSesInfo->capabilities = pSesInfo->server->capabilities;
3405 if(linuxExtEnabled == 0)
3406 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003407 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3409 pSesInfo->server->secMode,
3410 pSesInfo->server->capabilities,
3411 pSesInfo->server->timeZone));
3412 if (extended_security
3413 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3414 && (pSesInfo->server->secType == NTLMSSP)) {
3415 cFYI(1, ("New style sesssetup "));
3416 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3417 NULL /* security blob */,
3418 0 /* blob length */,
3419 nls_info);
3420 } else if (extended_security
3421 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3422 && (pSesInfo->server->secType == RawNTLMSSP)) {
3423 cFYI(1, ("NTLMSSP sesssetup "));
3424 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3425 pSesInfo,
3426 &ntlmv2_flag,
3427 nls_info);
3428 if (!rc) {
3429 if(ntlmv2_flag) {
3430 char * v2_response;
3431 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3432 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3433 nls_info)) {
3434 rc = -ENOMEM;
3435 goto ss_err_exit;
3436 } else
3437 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3438 if(v2_response) {
3439 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003440 /* if(first_time)
3441 cifs_calculate_ntlmv2_mac_key(
3442 pSesInfo->server->mac_signing_key,
3443 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 kfree(v2_response);
3445 /* BB Put dummy sig in SessSetup PDU? */
3446 } else {
3447 rc = -ENOMEM;
3448 goto ss_err_exit;
3449 }
3450
3451 } else {
3452 SMBNTencrypt(pSesInfo->password,
3453 pSesInfo->server->cryptKey,
3454 ntlm_session_key);
3455
Steve Frenchad009ac2005-04-28 22:41:05 -07003456 if(first_time)
3457 cifs_calculate_mac_key(
3458 pSesInfo->server->mac_signing_key,
3459 ntlm_session_key,
3460 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 }
3462 /* for better security the weaker lanman hash not sent
3463 in AuthSessSetup so we no longer calculate it */
3464
3465 rc = CIFSNTLMSSPAuthSessSetup(xid,
3466 pSesInfo,
3467 ntlm_session_key,
3468 ntlmv2_flag,
3469 nls_info);
3470 }
3471 } else { /* old style NTLM 0.12 session setup */
3472 SMBNTencrypt(pSesInfo->password,
3473 pSesInfo->server->cryptKey,
3474 ntlm_session_key);
3475
Steve Frenchad009ac2005-04-28 22:41:05 -07003476 if(first_time)
3477 cifs_calculate_mac_key(
3478 pSesInfo->server->mac_signing_key,
3479 ntlm_session_key, pSesInfo->password);
3480
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 rc = CIFSSessSetup(xid, pSesInfo,
3482 ntlm_session_key, nls_info);
3483 }
3484 if (rc) {
3485 cERROR(1,("Send error in SessSetup = %d",rc));
3486 } else {
3487 cFYI(1,("CIFS Session Established successfully"));
3488 pSesInfo->status = CifsGood;
3489 }
3490 }
3491ss_err_exit:
3492 return rc;
3493}
3494