blob: d1c6acee620e529580152b8371fb0d082487f1a7 [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 French0ae0efa2005-10-10 10:57:19 -0700192 cERROR(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 */
Steve French0ae0efa2005-10-10 10:57:19 -0700474 cERROR(1,("sleep before reconnect"));
Steve French46810cb2005-04-28 22:41:09 -0700475 msleep(1000);
476 /* always try 445 first on reconnect
477 since we get NACK on some if we ever
478 connected to port 139 (the NACK is
479 since we do not begin with RFC1001
480 session initialize frame) */
481 server->addr.sockAddr.sin_port =
482 htons(CIFS_PORT);
483 cifs_reconnect(server);
484 csocket = server->ssocket;
485 wake_up(&server->response_q);
486 continue;
487 }
Steve French70ca7342005-09-22 16:32:06 -0700488 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700489 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700490 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
491 length);
Steve French46810cb2005-04-28 22:41:09 -0700492 cifs_reconnect(server);
493 csocket = server->ssocket;
494 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700495 }
496
497 /* else we have an SMB response */
498 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700499 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700500 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700501 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700502 cifs_reconnect(server);
503 csocket = server->ssocket;
504 wake_up(&server->response_q);
505 continue;
506 }
507
508 /* else length ok */
509 reconnect = 0;
510
511 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
512 isLargeBuf = TRUE;
513 memcpy(bigbuf, smallbuf, 4);
514 smb_buffer = bigbuf;
515 }
516 length = 0;
517 iov.iov_base = 4 + (char *)smb_buffer;
518 iov.iov_len = pdu_length;
519 for (total_read = 0; total_read < pdu_length;
520 total_read += length) {
521 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
522 pdu_length - total_read, 0);
523 if((server->tcpStatus == CifsExiting) ||
524 (length == -EINTR)) {
525 /* then will exit */
526 reconnect = 2;
527 break;
528 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700529 cifs_reconnect(server);
530 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 /* Reconnect wakes up rspns q */
532 /* Now we will reread sock */
533 reconnect = 1;
534 break;
535 } else if ((length == -ERESTARTSYS) ||
536 (length == -EAGAIN)) {
537 msleep(1); /* minimum sleep to prevent looping,
538 allowing socket to clear and app
539 threads to set tcpStatus
540 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700541 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700542 } else if (length <= 0) {
543 cERROR(1,("Received no data, expecting %d",
544 pdu_length - total_read));
545 cifs_reconnect(server);
546 csocket = server->ssocket;
547 reconnect = 1;
548 break;
Steve French46810cb2005-04-28 22:41:09 -0700549 }
550 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 if(reconnect == 2)
552 break;
553 else if(reconnect == 1)
554 continue;
555
556 length += 4; /* account for rfc1002 hdr */
557
558
559 dump_smb(smb_buffer, length);
560 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
561 cERROR(1, ("Bad SMB Received "));
Steve French0ae0efa2005-10-10 10:57:19 -0700562 cifs_dump_mem("smb: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700563 continue;
564 }
565
566
567 task_to_wake = NULL;
568 spin_lock(&GlobalMid_Lock);
569 list_for_each(tmp, &server->pending_mid_q) {
570 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
571
572 if ((mid_entry->mid == smb_buffer->Mid) &&
573 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
574 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700575 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
576 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700577 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 if(mid_entry->resp_buf) {
579 /* merge response - fix up 1st*/
580 if(coalesce_t2(smb_buffer,
581 mid_entry->resp_buf)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700582 break;
583 } else {
584 /* all parts received */
585 goto multi_t2_fnd;
586 }
587 } else {
588 if(!isLargeBuf) {
589 cERROR(1,("1st trans2 resp needs bigbuf"));
590 /* BB maybe we can fix this up, switch
591 to already allocated large buffer? */
592 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700593 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700594 mid_entry->resp_buf =
595 smb_buffer;
596 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700597 bigbuf = NULL;
598 }
599 }
600 break;
601 }
602 mid_entry->resp_buf = smb_buffer;
603 if(isLargeBuf)
604 mid_entry->largeBuf = 1;
605 else
606 mid_entry->largeBuf = 0;
607multi_t2_fnd:
608 task_to_wake = mid_entry->tsk;
609 mid_entry->midState = MID_RESPONSE_RECEIVED;
610 break;
611 }
612 }
613 spin_unlock(&GlobalMid_Lock);
614 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700615 /* Was previous buf put in mpx struct for multi-rsp? */
616 if(!isMultiRsp) {
617 /* smb buffer will be freed by user thread */
618 if(isLargeBuf) {
619 bigbuf = NULL;
620 } else
621 smallbuf = NULL;
622 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700623 wake_up_process(task_to_wake);
Steve French57337e42005-04-28 22:41:10 -0700624 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700625 && (isMultiRsp == FALSE)) {
626 cERROR(1, ("No task to wake, unknown frame rcvd!"));
Steve French70ca7342005-09-22 16:32:06 -0700627 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
628 sizeof(struct smb_hdr));
Steve Frenche4eb2952005-04-28 22:41:09 -0700629 }
630 } /* end while !EXITING */
631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 spin_lock(&GlobalMid_Lock);
633 server->tcpStatus = CifsExiting;
634 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700635 /* check if we have blocked requests that need to free */
636 /* Note that cifs_max_pending is normally 50, but
637 can be set at module install time to as little as two */
638 if(atomic_read(&server->inFlight) >= cifs_max_pending)
639 atomic_set(&server->inFlight, cifs_max_pending - 1);
640 /* We do not want to set the max_pending too low or we
641 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 spin_unlock(&GlobalMid_Lock);
643 /* Although there should not be any requests blocked on
644 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700645 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 to the same server - they now will see the session is in exit state
647 and get out of SendReceive. */
648 wake_up_all(&server->request_q);
649 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700650 msleep(125);
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if(server->ssocket) {
653 sock_release(csocket);
654 server->ssocket = NULL;
655 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700656 /* buffer usuallly freed in free_mid - need to free it here on exit */
657 if (bigbuf != NULL)
658 cifs_buf_release(bigbuf);
659 if (smallbuf != NULL)
660 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662 read_lock(&GlobalSMBSeslock);
663 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700664 /* loop through server session structures attached to this and
665 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 list_for_each(tmp, &GlobalSMBSessionList) {
667 ses =
668 list_entry(tmp, struct cifsSesInfo,
669 cifsSessionList);
670 if (ses->server == server) {
671 ses->status = CifsExiting;
672 ses->server = NULL;
673 }
674 }
675 read_unlock(&GlobalSMBSeslock);
676 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700677 /* although we can not zero the server struct pointer yet,
678 since there are active requests which may depnd on them,
679 mark the corresponding SMB sessions as exiting too */
680 list_for_each(tmp, &GlobalSMBSessionList) {
681 ses = list_entry(tmp, struct cifsSesInfo,
682 cifsSessionList);
683 if (ses->server == server) {
684 ses->status = CifsExiting;
685 }
686 }
687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 spin_lock(&GlobalMid_Lock);
689 list_for_each(tmp, &server->pending_mid_q) {
690 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
691 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
692 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700693 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 task_to_wake = mid_entry->tsk;
695 if(task_to_wake) {
696 wake_up_process(task_to_wake);
697 }
698 }
699 }
700 spin_unlock(&GlobalMid_Lock);
701 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700703 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 }
705
Steve Frenchf1914012005-08-18 09:37:34 -0700706 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* mpx threads have not exited yet give them
708 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700709 /* due to delays on oplock break requests, we need
710 to wait at least 45 seconds before giving up
711 on a request getting a response and going ahead
712 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700714 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 /* if threads still have not exited they are probably never
716 coming home not much else we can do but free the memory */
717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 write_lock(&GlobalSMBSeslock);
720 atomic_dec(&tcpSesAllocCount);
721 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700722
723 /* last chance to mark ses pointers invalid
724 if there are any pointing to this (e.g
725 if a crazy root user tried to kill cifsd
726 kernel thread explicitly this might happen) */
727 list_for_each(tmp, &GlobalSMBSessionList) {
728 ses = list_entry(tmp, struct cifsSesInfo,
729 cifsSessionList);
730 if (ses->server == server) {
731 ses->server = NULL;
732 }
733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700735
736 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 if(length > 0) {
738 mempool_resize(cifs_req_poolp,
739 length + cifs_min_rcv,
740 GFP_KERNEL);
741 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700742
Steve Frenchf1914012005-08-18 09:37:34 -0700743 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return 0;
745}
746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747static int
748cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
749{
750 char *value;
751 char *data;
752 unsigned int temp_len, i, j;
753 char separator[2];
754
755 separator[0] = ',';
756 separator[1] = 0;
757
758 memset(vol->source_rfc1001_name,0x20,15);
759 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
760 /* does not have to be a perfect mapping since the field is
761 informational, only used for servers that do not support
762 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700763 vol->source_rfc1001_name[i] =
764 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 }
766 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700767 /* null target name indicates to use *SMBSERVR default called name
768 if we end up sending RFC1001 session initialize */
769 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 vol->linux_uid = current->uid; /* current->euid instead? */
771 vol->linux_gid = current->gid;
772 vol->dir_mode = S_IRWXUGO;
773 /* 2767 perms indicate mandatory locking support */
774 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
775
776 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
777 vol->rw = TRUE;
778
Jeremy Allisonac670552005-06-22 17:26:35 -0700779 /* default is always to request posix paths. */
780 vol->posix_paths = 1;
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (!options)
783 return 1;
784
785 if(strncmp(options,"sep=",4) == 0) {
786 if(options[4] != 0) {
787 separator[0] = options[4];
788 options += 5;
789 } else {
790 cFYI(1,("Null separator not allowed"));
791 }
792 }
793
794 while ((data = strsep(&options, separator)) != NULL) {
795 if (!*data)
796 continue;
797 if ((value = strchr(data, '=')) != NULL)
798 *value++ = '\0';
799
800 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
801 vol->no_xattr = 0;
802 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
803 vol->no_xattr = 1;
804 } else if (strnicmp(data, "user", 4) == 0) {
805 if (!value || !*value) {
806 printk(KERN_WARNING
807 "CIFS: invalid or missing username\n");
808 return 1; /* needs_arg; */
809 }
810 if (strnlen(value, 200) < 200) {
811 vol->username = value;
812 } else {
813 printk(KERN_WARNING "CIFS: username too long\n");
814 return 1;
815 }
816 } else if (strnicmp(data, "pass", 4) == 0) {
817 if (!value) {
818 vol->password = NULL;
819 continue;
820 } else if(value[0] == 0) {
821 /* check if string begins with double comma
822 since that would mean the password really
823 does start with a comma, and would not
824 indicate an empty string */
825 if(value[1] != separator[0]) {
826 vol->password = NULL;
827 continue;
828 }
829 }
830 temp_len = strlen(value);
831 /* removed password length check, NTLM passwords
832 can be arbitrarily long */
833
834 /* if comma in password, the string will be
835 prematurely null terminated. Commas in password are
836 specified across the cifs mount interface by a double
837 comma ie ,, and a comma used as in other cases ie ','
838 as a parameter delimiter/separator is single and due
839 to the strsep above is temporarily zeroed. */
840
841 /* NB: password legally can have multiple commas and
842 the only illegal character in a password is null */
843
Steve French09d1db52005-04-28 22:41:08 -0700844 if ((value[temp_len] == 0) &&
845 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 /* reinsert comma */
847 value[temp_len] = separator[0];
848 temp_len+=2; /* move after the second comma */
849 while(value[temp_len] != 0) {
850 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700851 if (value[temp_len+1] ==
852 separator[0]) {
853 /* skip second comma */
854 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 } else {
856 /* single comma indicating start
857 of next parm */
858 break;
859 }
860 }
861 temp_len++;
862 }
863 if(value[temp_len] == 0) {
864 options = NULL;
865 } else {
866 value[temp_len] = 0;
867 /* point option to start of next parm */
868 options = value + temp_len + 1;
869 }
870 /* go from value to value + temp_len condensing
871 double commas to singles. Note that this ends up
872 allocating a few bytes too many, which is ok */
Steve French433dc242005-04-28 22:41:08 -0700873 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
874 if(vol->password == NULL) {
875 printk("CIFS: no memory for pass\n");
876 return 1;
877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 for(i=0,j=0;i<temp_len;i++,j++) {
879 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700880 if(value[i] == separator[0]
881 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 /* skip second comma */
883 i++;
884 }
885 }
886 vol->password[j] = 0;
887 } else {
Steve French09d1db52005-04-28 22:41:08 -0700888 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700889 if(vol->password == NULL) {
890 printk("CIFS: no memory for pass\n");
891 return 1;
892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 strcpy(vol->password, value);
894 }
895 } else if (strnicmp(data, "ip", 2) == 0) {
896 if (!value || !*value) {
897 vol->UNCip = NULL;
898 } else if (strnlen(value, 35) < 35) {
899 vol->UNCip = value;
900 } else {
901 printk(KERN_WARNING "CIFS: ip address too long\n");
902 return 1;
903 }
904 } else if ((strnicmp(data, "unc", 3) == 0)
905 || (strnicmp(data, "target", 6) == 0)
906 || (strnicmp(data, "path", 4) == 0)) {
907 if (!value || !*value) {
908 printk(KERN_WARNING
909 "CIFS: invalid path to network resource\n");
910 return 1; /* needs_arg; */
911 }
912 if ((temp_len = strnlen(value, 300)) < 300) {
913 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
914 if(vol->UNC == NULL)
915 return 1;
916 strcpy(vol->UNC,value);
917 if (strncmp(vol->UNC, "//", 2) == 0) {
918 vol->UNC[0] = '\\';
919 vol->UNC[1] = '\\';
920 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
921 printk(KERN_WARNING
922 "CIFS: UNC Path does not begin with // or \\\\ \n");
923 return 1;
924 }
925 } else {
926 printk(KERN_WARNING "CIFS: UNC name too long\n");
927 return 1;
928 }
929 } else if ((strnicmp(data, "domain", 3) == 0)
930 || (strnicmp(data, "workgroup", 5) == 0)) {
931 if (!value || !*value) {
932 printk(KERN_WARNING "CIFS: invalid domain name\n");
933 return 1; /* needs_arg; */
934 }
935 /* BB are there cases in which a comma can be valid in
936 a domain name and need special handling? */
937 if (strnlen(value, 65) < 65) {
938 vol->domainname = value;
939 cFYI(1, ("Domain name set"));
940 } else {
941 printk(KERN_WARNING "CIFS: domain name too long\n");
942 return 1;
943 }
944 } else if (strnicmp(data, "iocharset", 9) == 0) {
945 if (!value || !*value) {
946 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
947 return 1; /* needs_arg; */
948 }
949 if (strnlen(value, 65) < 65) {
950 if(strnicmp(value,"default",7))
951 vol->iocharset = value;
952 /* if iocharset not set load_nls_default used by caller */
953 cFYI(1, ("iocharset set to %s",value));
954 } else {
955 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
956 return 1;
957 }
958 } else if (strnicmp(data, "uid", 3) == 0) {
959 if (value && *value) {
960 vol->linux_uid =
961 simple_strtoul(value, &value, 0);
962 }
963 } else if (strnicmp(data, "gid", 3) == 0) {
964 if (value && *value) {
965 vol->linux_gid =
966 simple_strtoul(value, &value, 0);
967 }
968 } else if (strnicmp(data, "file_mode", 4) == 0) {
969 if (value && *value) {
970 vol->file_mode =
971 simple_strtoul(value, &value, 0);
972 }
973 } else if (strnicmp(data, "dir_mode", 4) == 0) {
974 if (value && *value) {
975 vol->dir_mode =
976 simple_strtoul(value, &value, 0);
977 }
978 } else if (strnicmp(data, "dirmode", 4) == 0) {
979 if (value && *value) {
980 vol->dir_mode =
981 simple_strtoul(value, &value, 0);
982 }
983 } else if (strnicmp(data, "port", 4) == 0) {
984 if (value && *value) {
985 vol->port =
986 simple_strtoul(value, &value, 0);
987 }
988 } else if (strnicmp(data, "rsize", 5) == 0) {
989 if (value && *value) {
990 vol->rsize =
991 simple_strtoul(value, &value, 0);
992 }
993 } else if (strnicmp(data, "wsize", 5) == 0) {
994 if (value && *value) {
995 vol->wsize =
996 simple_strtoul(value, &value, 0);
997 }
998 } else if (strnicmp(data, "sockopt", 5) == 0) {
999 if (value && *value) {
1000 vol->sockopt =
1001 simple_strtoul(value, &value, 0);
1002 }
1003 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1004 if (!value || !*value || (*value == ' ')) {
1005 cFYI(1,("invalid (empty) netbiosname specified"));
1006 } else {
1007 memset(vol->source_rfc1001_name,0x20,15);
1008 for(i=0;i<15;i++) {
1009 /* BB are there cases in which a comma can be
1010 valid in this workstation netbios name (and need
1011 special handling)? */
1012
1013 /* We do not uppercase netbiosname for user */
1014 if (value[i]==0)
1015 break;
1016 else
1017 vol->source_rfc1001_name[i] = value[i];
1018 }
1019 /* The string has 16th byte zero still from
1020 set at top of the function */
1021 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001022 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1023 }
1024 } else if (strnicmp(data, "servern", 7) == 0) {
1025 /* servernetbiosname specified override *SMBSERVER */
1026 if (!value || !*value || (*value == ' ')) {
1027 cFYI(1,("empty server netbiosname specified"));
1028 } else {
1029 /* last byte, type, is 0x20 for servr type */
1030 memset(vol->target_rfc1001_name,0x20,16);
1031
1032 for(i=0;i<15;i++) {
1033 /* BB are there cases in which a comma can be
1034 valid in this workstation netbios name (and need
1035 special handling)? */
1036
1037 /* user or mount helper must uppercase netbiosname */
1038 if (value[i]==0)
1039 break;
1040 else
1041 vol->target_rfc1001_name[i] = value[i];
1042 }
1043 /* The string has 16th byte zero still from
1044 set at top of the function */
1045 if((i==15) && (value[i] != 0))
1046 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
1048 } else if (strnicmp(data, "credentials", 4) == 0) {
1049 /* ignore */
1050 } else if (strnicmp(data, "version", 3) == 0) {
1051 /* ignore */
1052 } else if (strnicmp(data, "guest",5) == 0) {
1053 /* ignore */
1054 } else if (strnicmp(data, "rw", 2) == 0) {
1055 vol->rw = TRUE;
1056 } else if ((strnicmp(data, "suid", 4) == 0) ||
1057 (strnicmp(data, "nosuid", 6) == 0) ||
1058 (strnicmp(data, "exec", 4) == 0) ||
1059 (strnicmp(data, "noexec", 6) == 0) ||
1060 (strnicmp(data, "nodev", 5) == 0) ||
1061 (strnicmp(data, "noauto", 6) == 0) ||
1062 (strnicmp(data, "dev", 3) == 0)) {
1063 /* The mount tool or mount.cifs helper (if present)
1064 uses these opts to set flags, and the flags are read
1065 by the kernel vfs layer before we get here (ie
1066 before read super) so there is no point trying to
1067 parse these options again and set anything and it
1068 is ok to just ignore them */
1069 continue;
1070 } else if (strnicmp(data, "ro", 2) == 0) {
1071 vol->rw = FALSE;
1072 } else if (strnicmp(data, "hard", 4) == 0) {
1073 vol->retry = 1;
1074 } else if (strnicmp(data, "soft", 4) == 0) {
1075 vol->retry = 0;
1076 } else if (strnicmp(data, "perm", 4) == 0) {
1077 vol->noperm = 0;
1078 } else if (strnicmp(data, "noperm", 6) == 0) {
1079 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001080 } else if (strnicmp(data, "mapchars", 8) == 0) {
1081 vol->remap = 1;
1082 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1083 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001084 } else if (strnicmp(data, "sfu", 3) == 0) {
1085 vol->sfu_emul = 1;
1086 } else if (strnicmp(data, "nosfu", 5) == 0) {
1087 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001088 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1089 vol->posix_paths = 1;
1090 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1091 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001092 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1093 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001094 vol->nocase = 1;
1095 } else if (strnicmp(data, "brl", 3) == 0) {
1096 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001097 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001098 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001099 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001100 /* turn off mandatory locking in mode
1101 if remote locking is turned off since the
1102 local vfs will do advisory */
1103 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1104 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 } else if (strnicmp(data, "setuids", 7) == 0) {
1106 vol->setuids = 1;
1107 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1108 vol->setuids = 0;
1109 } else if (strnicmp(data, "nohard", 6) == 0) {
1110 vol->retry = 0;
1111 } else if (strnicmp(data, "nosoft", 6) == 0) {
1112 vol->retry = 1;
1113 } else if (strnicmp(data, "nointr", 6) == 0) {
1114 vol->intr = 0;
1115 } else if (strnicmp(data, "intr", 4) == 0) {
1116 vol->intr = 1;
1117 } else if (strnicmp(data, "serverino",7) == 0) {
1118 vol->server_ino = 1;
1119 } else if (strnicmp(data, "noserverino",9) == 0) {
1120 vol->server_ino = 0;
1121 } else if (strnicmp(data, "acl",3) == 0) {
1122 vol->no_psx_acl = 0;
1123 } else if (strnicmp(data, "noacl",5) == 0) {
1124 vol->no_psx_acl = 1;
1125 } else if (strnicmp(data, "direct",6) == 0) {
1126 vol->direct_io = 1;
1127 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1128 vol->direct_io = 1;
1129 } else if (strnicmp(data, "in6_addr",8) == 0) {
1130 if (!value || !*value) {
1131 vol->in6_addr = NULL;
1132 } else if (strnlen(value, 49) == 48) {
1133 vol->in6_addr = value;
1134 } else {
1135 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1136 return 1;
1137 }
1138 } else if (strnicmp(data, "noac", 4) == 0) {
1139 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1140 } else
1141 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1142 }
1143 if (vol->UNC == NULL) {
1144 if(devname == NULL) {
1145 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1146 return 1;
1147 }
1148 if ((temp_len = strnlen(devname, 300)) < 300) {
1149 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1150 if(vol->UNC == NULL)
1151 return 1;
1152 strcpy(vol->UNC,devname);
1153 if (strncmp(vol->UNC, "//", 2) == 0) {
1154 vol->UNC[0] = '\\';
1155 vol->UNC[1] = '\\';
1156 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1157 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1158 return 1;
1159 }
1160 } else {
1161 printk(KERN_WARNING "CIFS: UNC name too long\n");
1162 return 1;
1163 }
1164 }
1165 if(vol->UNCip == NULL)
1166 vol->UNCip = &vol->UNC[2];
1167
1168 return 0;
1169}
1170
1171static struct cifsSesInfo *
1172cifs_find_tcp_session(struct in_addr * target_ip_addr,
1173 struct in6_addr *target_ip6_addr,
1174 char *userName, struct TCP_Server_Info **psrvTcp)
1175{
1176 struct list_head *tmp;
1177 struct cifsSesInfo *ses;
1178 *psrvTcp = NULL;
1179 read_lock(&GlobalSMBSeslock);
1180
1181 list_for_each(tmp, &GlobalSMBSessionList) {
1182 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1183 if (ses->server) {
1184 if((target_ip_addr &&
1185 (ses->server->addr.sockAddr.sin_addr.s_addr
1186 == target_ip_addr->s_addr)) || (target_ip6_addr
1187 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1188 target_ip6_addr,sizeof(*target_ip6_addr)))){
1189 /* BB lock server and tcp session and increment use count here?? */
1190 *psrvTcp = ses->server; /* found a match on the TCP session */
1191 /* BB check if reconnection needed */
1192 if (strncmp
1193 (ses->userName, userName,
1194 MAX_USERNAME_SIZE) == 0){
1195 read_unlock(&GlobalSMBSeslock);
1196 return ses; /* found exact match on both tcp and SMB sessions */
1197 }
1198 }
1199 }
1200 /* else tcp and smb sessions need reconnection */
1201 }
1202 read_unlock(&GlobalSMBSeslock);
1203 return NULL;
1204}
1205
1206static struct cifsTconInfo *
1207find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1208{
1209 struct list_head *tmp;
1210 struct cifsTconInfo *tcon;
1211
1212 read_lock(&GlobalSMBSeslock);
1213 list_for_each(tmp, &GlobalTreeConnectionList) {
1214 cFYI(1, ("Next tcon - "));
1215 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1216 if (tcon->ses) {
1217 if (tcon->ses->server) {
1218 cFYI(1,
1219 (" old ip addr: %x == new ip %x ?",
1220 tcon->ses->server->addr.sockAddr.sin_addr.
1221 s_addr, new_target_ip_addr));
1222 if (tcon->ses->server->addr.sockAddr.sin_addr.
1223 s_addr == new_target_ip_addr) {
1224 /* BB lock tcon and server and tcp session and increment use count here? */
1225 /* found a match on the TCP session */
1226 /* BB check if reconnection needed */
1227 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1228 tcon->treeName, uncName));
1229 if (strncmp
1230 (tcon->treeName, uncName,
1231 MAX_TREE_SIZE) == 0) {
1232 cFYI(1,
1233 ("Matched UNC, old user: %s == new: %s ?",
1234 tcon->treeName, uncName));
1235 if (strncmp
1236 (tcon->ses->userName,
1237 userName,
1238 MAX_USERNAME_SIZE) == 0) {
1239 read_unlock(&GlobalSMBSeslock);
1240 return tcon;/* also matched user (smb session)*/
1241 }
1242 }
1243 }
1244 }
1245 }
1246 }
1247 read_unlock(&GlobalSMBSeslock);
1248 return NULL;
1249}
1250
1251int
1252connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001253 const char *old_path, const struct nls_table *nls_codepage,
1254 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255{
1256 unsigned char *referrals = NULL;
1257 unsigned int num_referrals;
1258 int rc = 0;
1259
1260 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001261 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
1263 /* BB Add in code to: if valid refrl, if not ip address contact
1264 the helper that resolves tcp names, mount to it, try to
1265 tcon to it unmount it if fail */
1266
1267 if(referrals)
1268 kfree(referrals);
1269
1270 return rc;
1271}
1272
1273int
1274get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1275 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001276 unsigned int *pnum_referrals,
1277 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
1279 char *temp_unc;
1280 int rc = 0;
1281
1282 *pnum_referrals = 0;
1283
1284 if (pSesInfo->ipc_tid == 0) {
1285 temp_unc = kmalloc(2 /* for slashes */ +
1286 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1287 + 1 + 4 /* slash IPC$ */ + 2,
1288 GFP_KERNEL);
1289 if (temp_unc == NULL)
1290 return -ENOMEM;
1291 temp_unc[0] = '\\';
1292 temp_unc[1] = '\\';
1293 strcpy(temp_unc + 2, pSesInfo->serverName);
1294 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1295 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1296 cFYI(1,
1297 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1298 kfree(temp_unc);
1299 }
1300 if (rc == 0)
1301 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001302 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
1304 return rc;
1305}
1306
1307/* See RFC1001 section 14 on representation of Netbios names */
1308static void rfc1002mangle(char * target,char * source, unsigned int length)
1309{
1310 unsigned int i,j;
1311
1312 for(i=0,j=0;i<(length);i++) {
1313 /* mask a nibble at a time and encode */
1314 target[j] = 'A' + (0x0F & (source[i] >> 4));
1315 target[j+1] = 'A' + (0x0F & source[i]);
1316 j+=2;
1317 }
1318
1319}
1320
1321
1322static int
1323ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001324 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325{
1326 int rc = 0;
1327 int connected = 0;
1328 __be16 orig_port = 0;
1329
1330 if(*csocket == NULL) {
1331 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1332 if (rc < 0) {
1333 cERROR(1, ("Error %d creating socket",rc));
1334 *csocket = NULL;
1335 return rc;
1336 } else {
1337 /* BB other socket options to set KEEPALIVE, NODELAY? */
1338 cFYI(1,("Socket created"));
1339 (*csocket)->sk->sk_allocation = GFP_NOFS;
1340 }
1341 }
1342
1343 psin_server->sin_family = AF_INET;
1344 if(psin_server->sin_port) { /* user overrode default port */
1345 rc = (*csocket)->ops->connect(*csocket,
1346 (struct sockaddr *) psin_server,
1347 sizeof (struct sockaddr_in),0);
1348 if (rc >= 0)
1349 connected = 1;
1350 }
1351
1352 if(!connected) {
1353 /* save original port so we can retry user specified port
1354 later if fall back ports fail this time */
1355 orig_port = psin_server->sin_port;
1356
1357 /* do not retry on the same port we just failed on */
1358 if(psin_server->sin_port != htons(CIFS_PORT)) {
1359 psin_server->sin_port = htons(CIFS_PORT);
1360
1361 rc = (*csocket)->ops->connect(*csocket,
1362 (struct sockaddr *) psin_server,
1363 sizeof (struct sockaddr_in),0);
1364 if (rc >= 0)
1365 connected = 1;
1366 }
1367 }
1368 if (!connected) {
1369 psin_server->sin_port = htons(RFC1001_PORT);
1370 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1371 psin_server, sizeof (struct sockaddr_in),0);
1372 if (rc >= 0)
1373 connected = 1;
1374 }
1375
1376 /* give up here - unless we want to retry on different
1377 protocol families some day */
1378 if (!connected) {
1379 if(orig_port)
1380 psin_server->sin_port = orig_port;
1381 cFYI(1,("Error %d connecting to server via ipv4",rc));
1382 sock_release(*csocket);
1383 *csocket = NULL;
1384 return rc;
1385 }
1386 /* Eventually check for other socket options to change from
1387 the default. sock_setsockopt not used because it expects
1388 user space buffer */
1389 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French0ae0efa2005-10-10 10:57:19 -07001390 cERROR(1,("sndbuf %d rcvbuf %d reset to 200K each",(*csocket)->sk->sk_sndbuf, (*csocket)->sk->sk_rcvbuf));
1391 (*csocket)->sk->sk_sndbuf = 300 * 1024;
1392 (*csocket)->sk->sk_rcvbuf = 200 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 /* send RFC1001 sessinit */
1394
1395 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1396 /* some servers require RFC1001 sessinit before sending
1397 negprot - BB check reconnection in case where second
1398 sessinit is sent but no second negprot */
1399 struct rfc1002_session_packet * ses_init_buf;
1400 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001401 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 if(ses_init_buf) {
1403 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001404 if(target_name && (target_name[0] != 0)) {
1405 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1406 target_name, 16);
1407 } else {
1408 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1409 DEFAULT_CIFS_CALLED_NAME,16);
1410 }
1411
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 ses_init_buf->trailer.session_req.calling_len = 32;
1413 /* calling name ends in null (byte 16) from old smb
1414 convention. */
1415 if(netbios_name && (netbios_name[0] !=0)) {
1416 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1417 netbios_name,16);
1418 } else {
1419 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1420 "LINUX_CIFS_CLNT",16);
1421 }
1422 ses_init_buf->trailer.session_req.scope1 = 0;
1423 ses_init_buf->trailer.session_req.scope2 = 0;
1424 smb_buf = (struct smb_hdr *)ses_init_buf;
1425 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1426 smb_buf->smb_buf_length = 0x81000044;
1427 rc = smb_send(*csocket, smb_buf, 0x44,
1428 (struct sockaddr *)psin_server);
1429 kfree(ses_init_buf);
1430 }
1431 /* else the negprot may still work without this
1432 even though malloc failed */
1433
1434 }
1435
1436 return rc;
1437}
1438
1439static int
1440ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1441{
1442 int rc = 0;
1443 int connected = 0;
1444 __be16 orig_port = 0;
1445
1446 if(*csocket == NULL) {
1447 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1448 if (rc < 0) {
1449 cERROR(1, ("Error %d creating ipv6 socket",rc));
1450 *csocket = NULL;
1451 return rc;
1452 } else {
1453 /* BB other socket options to set KEEPALIVE, NODELAY? */
1454 cFYI(1,("ipv6 Socket created"));
1455 (*csocket)->sk->sk_allocation = GFP_NOFS;
1456 }
1457 }
1458
1459 psin_server->sin6_family = AF_INET6;
1460
1461 if(psin_server->sin6_port) { /* user overrode default port */
1462 rc = (*csocket)->ops->connect(*csocket,
1463 (struct sockaddr *) psin_server,
1464 sizeof (struct sockaddr_in6),0);
1465 if (rc >= 0)
1466 connected = 1;
1467 }
1468
1469 if(!connected) {
1470 /* save original port so we can retry user specified port
1471 later if fall back ports fail this time */
1472
1473 orig_port = psin_server->sin6_port;
1474 /* do not retry on the same port we just failed on */
1475 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1476 psin_server->sin6_port = htons(CIFS_PORT);
1477
1478 rc = (*csocket)->ops->connect(*csocket,
1479 (struct sockaddr *) psin_server,
1480 sizeof (struct sockaddr_in6),0);
1481 if (rc >= 0)
1482 connected = 1;
1483 }
1484 }
1485 if (!connected) {
1486 psin_server->sin6_port = htons(RFC1001_PORT);
1487 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1488 psin_server, sizeof (struct sockaddr_in6),0);
1489 if (rc >= 0)
1490 connected = 1;
1491 }
1492
1493 /* give up here - unless we want to retry on different
1494 protocol families some day */
1495 if (!connected) {
1496 if(orig_port)
1497 psin_server->sin6_port = orig_port;
1498 cFYI(1,("Error %d connecting to server via ipv6",rc));
1499 sock_release(*csocket);
1500 *csocket = NULL;
1501 return rc;
1502 }
1503 /* Eventually check for other socket options to change from
1504 the default. sock_setsockopt not used because it expects
1505 user space buffer */
1506 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1507
1508 return rc;
1509}
1510
1511int
1512cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1513 char *mount_data, const char *devname)
1514{
1515 int rc = 0;
1516 int xid;
1517 int address_type = AF_INET;
1518 struct socket *csocket = NULL;
1519 struct sockaddr_in sin_server;
1520 struct sockaddr_in6 sin_server6;
1521 struct smb_vol volume_info;
1522 struct cifsSesInfo *pSesInfo = NULL;
1523 struct cifsSesInfo *existingCifsSes = NULL;
1524 struct cifsTconInfo *tcon = NULL;
1525 struct TCP_Server_Info *srvTcp = NULL;
1526
1527 xid = GetXid();
1528
1529/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1530
1531 memset(&volume_info,0,sizeof(struct smb_vol));
1532 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1533 if(volume_info.UNC)
1534 kfree(volume_info.UNC);
1535 if(volume_info.password)
1536 kfree(volume_info.password);
1537 FreeXid(xid);
1538 return -EINVAL;
1539 }
1540
1541 if (volume_info.username) {
1542 /* BB fixme parse for domain name here */
1543 cFYI(1, ("Username: %s ", volume_info.username));
1544
1545 } else {
1546 cifserror("No username specified ");
1547 /* In userspace mount helper we can get user name from alternate
1548 locations such as env variables and files on disk */
1549 if(volume_info.UNC)
1550 kfree(volume_info.UNC);
1551 if(volume_info.password)
1552 kfree(volume_info.password);
1553 FreeXid(xid);
1554 return -EINVAL;
1555 }
1556
1557 if (volume_info.UNCip && volume_info.UNC) {
1558 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1559
1560 if(rc <= 0) {
1561 /* not ipv4 address, try ipv6 */
1562 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1563 if(rc > 0)
1564 address_type = AF_INET6;
1565 } else {
1566 address_type = AF_INET;
1567 }
1568
1569 if(rc <= 0) {
1570 /* we failed translating address */
1571 if(volume_info.UNC)
1572 kfree(volume_info.UNC);
1573 if(volume_info.password)
1574 kfree(volume_info.password);
1575 FreeXid(xid);
1576 return -EINVAL;
1577 }
1578
1579 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1580 /* success */
1581 rc = 0;
1582 } else if (volume_info.UNCip){
1583 /* BB using ip addr as server name connect to the DFS root below */
1584 cERROR(1,("Connecting to DFS root not implemented yet"));
1585 if(volume_info.UNC)
1586 kfree(volume_info.UNC);
1587 if(volume_info.password)
1588 kfree(volume_info.password);
1589 FreeXid(xid);
1590 return -EINVAL;
1591 } else /* which servers DFS root would we conect to */ {
1592 cERROR(1,
1593 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1594 if(volume_info.UNC)
1595 kfree(volume_info.UNC);
1596 if(volume_info.password)
1597 kfree(volume_info.password);
1598 FreeXid(xid);
1599 return -EINVAL;
1600 }
1601
1602 /* this is needed for ASCII cp to Unicode converts */
1603 if(volume_info.iocharset == NULL) {
1604 cifs_sb->local_nls = load_nls_default();
1605 /* load_nls_default can not return null */
1606 } else {
1607 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1608 if(cifs_sb->local_nls == NULL) {
1609 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1610 if(volume_info.UNC)
1611 kfree(volume_info.UNC);
1612 if(volume_info.password)
1613 kfree(volume_info.password);
1614 FreeXid(xid);
1615 return -ELIBACC;
1616 }
1617 }
1618
1619 if(address_type == AF_INET)
1620 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1621 NULL /* no ipv6 addr */,
1622 volume_info.username, &srvTcp);
1623 else if(address_type == AF_INET6)
1624 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1625 &sin_server6.sin6_addr,
1626 volume_info.username, &srvTcp);
1627 else {
1628 if(volume_info.UNC)
1629 kfree(volume_info.UNC);
1630 if(volume_info.password)
1631 kfree(volume_info.password);
1632 FreeXid(xid);
1633 return -EINVAL;
1634 }
1635
1636
1637 if (srvTcp) {
1638 cFYI(1, ("Existing tcp session with server found "));
1639 } else { /* create socket */
1640 if(volume_info.port)
1641 sin_server.sin_port = htons(volume_info.port);
1642 else
1643 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001644 rc = ipv4_connect(&sin_server,&csocket,
1645 volume_info.source_rfc1001_name,
1646 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 if (rc < 0) {
1648 cERROR(1,
1649 ("Error connecting to IPv4 socket. Aborting operation"));
1650 if(csocket != NULL)
1651 sock_release(csocket);
1652 if(volume_info.UNC)
1653 kfree(volume_info.UNC);
1654 if(volume_info.password)
1655 kfree(volume_info.password);
1656 FreeXid(xid);
1657 return rc;
1658 }
1659
1660 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1661 if (srvTcp == NULL) {
1662 rc = -ENOMEM;
1663 sock_release(csocket);
1664 if(volume_info.UNC)
1665 kfree(volume_info.UNC);
1666 if(volume_info.password)
1667 kfree(volume_info.password);
1668 FreeXid(xid);
1669 return rc;
1670 } else {
1671 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1672 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1673 atomic_set(&srvTcp->inFlight,0);
1674 /* BB Add code for ipv6 case too */
1675 srvTcp->ssocket = csocket;
1676 srvTcp->protocolType = IPV4;
1677 init_waitqueue_head(&srvTcp->response_q);
1678 init_waitqueue_head(&srvTcp->request_q);
1679 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1680 /* at this point we are the only ones with the pointer
1681 to the struct since the kernel thread not created yet
1682 so no need to spinlock this init of tcpStatus */
1683 srvTcp->tcpStatus = CifsNew;
1684 init_MUTEX(&srvTcp->tcpSem);
1685 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1686 CLONE_FS | CLONE_FILES | CLONE_VM);
1687 if(rc < 0) {
1688 rc = -ENOMEM;
1689 sock_release(csocket);
1690 if(volume_info.UNC)
1691 kfree(volume_info.UNC);
1692 if(volume_info.password)
1693 kfree(volume_info.password);
1694 FreeXid(xid);
1695 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001696 }
1697 wait_for_completion(&cifsd_complete);
1698 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001700 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001701 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 }
1703 }
1704
1705 if (existingCifsSes) {
1706 pSesInfo = existingCifsSes;
1707 cFYI(1, ("Existing smb sess found "));
1708 if(volume_info.password)
1709 kfree(volume_info.password);
1710 /* volume_info.UNC freed at end of function */
1711 } else if (!rc) {
1712 cFYI(1, ("Existing smb sess not found "));
1713 pSesInfo = sesInfoAlloc();
1714 if (pSesInfo == NULL)
1715 rc = -ENOMEM;
1716 else {
1717 pSesInfo->server = srvTcp;
1718 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1719 NIPQUAD(sin_server.sin_addr.s_addr));
1720 }
1721
1722 if (!rc){
1723 /* volume_info.password freed at unmount */
1724 if (volume_info.password)
1725 pSesInfo->password = volume_info.password;
1726 if (volume_info.username)
1727 strncpy(pSesInfo->userName,
1728 volume_info.username,MAX_USERNAME_SIZE);
1729 if (volume_info.domainname)
1730 strncpy(pSesInfo->domainName,
1731 volume_info.domainname,MAX_USERNAME_SIZE);
1732 pSesInfo->linux_uid = volume_info.linux_uid;
1733 down(&pSesInfo->sesSem);
1734 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1735 up(&pSesInfo->sesSem);
1736 if(!rc)
1737 atomic_inc(&srvTcp->socketUseCount);
1738 } else
1739 if(volume_info.password)
1740 kfree(volume_info.password);
1741 }
1742
1743 /* search for existing tcon to this server share */
1744 if (!rc) {
Steve French0ae0efa2005-10-10 10:57:19 -07001745 if(volume_info.rsize > CIFSMaxBufSize) {
1746 cERROR(1,("rsize %d too large, using MaxBufSize",
1747 volume_info.rsize));
1748 cifs_sb->rsize = CIFSMaxBufSize;
1749 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001751 else /* default */
1752 cifs_sb->rsize = CIFSMaxBufSize;
1753
1754 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1755 cERROR(1,("wsize %d too large using 4096 instead",
1756 volume_info.wsize));
1757 cifs_sb->wsize = 4096;
1758 } else if(volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 cifs_sb->wsize = volume_info.wsize;
1760 else
1761 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1762 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
Steve French6b8edfe2005-08-23 20:26:03 -07001763 cifs_sb->rsize = PAGE_CACHE_SIZE;
1764 /* Windows ME does this */
1765 cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 }
1767 cifs_sb->mnt_uid = volume_info.linux_uid;
1768 cifs_sb->mnt_gid = volume_info.linux_gid;
1769 cifs_sb->mnt_file_mode = volume_info.file_mode;
1770 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1771 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1772
1773 if(volume_info.noperm)
1774 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1775 if(volume_info.setuids)
1776 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1777 if(volume_info.server_ino)
1778 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001779 if(volume_info.remap)
1780 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 if(volume_info.no_xattr)
1782 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001783 if(volume_info.sfu_emul)
1784 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001785 if(volume_info.nobrl)
1786 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001789 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1791 }
1792
1793 tcon =
1794 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1795 volume_info.username);
1796 if (tcon) {
1797 cFYI(1, ("Found match on UNC path "));
1798 /* we can have only one retry value for a connection
1799 to a share so for resources mounted more than once
1800 to the same server share the last value passed in
1801 for the retry flag is used */
1802 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001803 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 } else {
1805 tcon = tconInfoAlloc();
1806 if (tcon == NULL)
1807 rc = -ENOMEM;
1808 else {
1809 /* check for null share name ie connect to dfs root */
1810
1811 /* BB check if this works for exactly length three strings */
1812 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1813 && (strchr(volume_info.UNC + 3, '/') ==
1814 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001815 rc = connect_to_dfs_path(xid, pSesInfo,
1816 "", cifs_sb->local_nls,
1817 cifs_sb->mnt_cifs_flags &
1818 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 if(volume_info.UNC)
1820 kfree(volume_info.UNC);
1821 FreeXid(xid);
1822 return -ENODEV;
1823 } else {
1824 rc = CIFSTCon(xid, pSesInfo,
1825 volume_info.UNC,
1826 tcon, cifs_sb->local_nls);
1827 cFYI(1, ("CIFS Tcon rc = %d", rc));
1828 }
1829 if (!rc) {
1830 atomic_inc(&pSesInfo->inUse);
1831 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001832 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 }
1834 }
1835 }
1836 }
1837 if(pSesInfo) {
1838 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1839 sb->s_maxbytes = (u64) 1 << 63;
1840 } else
1841 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1842 }
1843
1844 sb->s_time_gran = 100;
1845
1846/* on error free sesinfo and tcon struct if needed */
1847 if (rc) {
1848 /* if session setup failed, use count is zero but
1849 we still need to free cifsd thread */
1850 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1851 spin_lock(&GlobalMid_Lock);
1852 srvTcp->tcpStatus = CifsExiting;
1853 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001854 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001856 wait_for_completion(&cifsd_complete);
1857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 }
1859 /* If find_unc succeeded then rc == 0 so we can not end */
1860 if (tcon) /* up accidently freeing someone elses tcon struct */
1861 tconInfoFree(tcon);
1862 if (existingCifsSes == NULL) {
1863 if (pSesInfo) {
1864 if ((pSesInfo->server) &&
1865 (pSesInfo->status == CifsGood)) {
1866 int temp_rc;
1867 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1868 /* if the socketUseCount is now zero */
1869 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001870 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001872 wait_for_completion(&cifsd_complete);
1873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 } else
1875 cFYI(1, ("No session or bad tcon"));
1876 sesInfoFree(pSesInfo);
1877 /* pSesInfo = NULL; */
1878 }
1879 }
1880 } else {
1881 atomic_inc(&tcon->useCount);
1882 cifs_sb->tcon = tcon;
1883 tcon->ses = pSesInfo;
1884
1885 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001886 CIFSSMBQFSDeviceInfo(xid, tcon);
1887 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001889 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if(!volume_info.no_psx_acl) {
1891 if(CIFS_UNIX_POSIX_ACL_CAP &
1892 le64_to_cpu(tcon->fsUnixInfo.Capability))
1893 cFYI(1,("server negotiated posix acl support"));
1894 sb->s_flags |= MS_POSIXACL;
1895 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001896
1897 /* Try and negotiate POSIX pathnames if we can. */
1898 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1899 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French45abc6e2005-06-23 13:42:03 -05001900 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
Jeremy Allisonac670552005-06-22 17:26:35 -07001901 cFYI(1,("negotiated posix pathnames support"));
1902 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1903 } else {
1904 cFYI(1,("posix pathnames support requested but not supported"));
1905 }
1906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 }
1908 }
Steve French3e844692005-10-03 13:37:24 -07001909 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
1910 cifs_sb->wsize = min(cifs_sb->wsize,
1911 (tcon->ses->server->maxBuf -
1912 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07001913 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
1914 cifs_sb->rsize = min(cifs_sb->rsize,
1915 (tcon->ses->server->maxBuf -
1916 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 }
1918
1919 /* volume_info.password is freed above when existing session found
1920 (in which case it is not needed anymore) but when new sesion is created
1921 the password ptr is put in the new session structure (in which case the
1922 password will be freed at unmount time) */
1923 if(volume_info.UNC)
1924 kfree(volume_info.UNC);
1925 FreeXid(xid);
1926 return rc;
1927}
1928
1929static int
1930CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1931 char session_key[CIFS_SESSION_KEY_SIZE],
1932 const struct nls_table *nls_codepage)
1933{
1934 struct smb_hdr *smb_buffer;
1935 struct smb_hdr *smb_buffer_response;
1936 SESSION_SETUP_ANDX *pSMB;
1937 SESSION_SETUP_ANDX *pSMBr;
1938 char *bcc_ptr;
1939 char *user;
1940 char *domain;
1941 int rc = 0;
1942 int remaining_words = 0;
1943 int bytes_returned = 0;
1944 int len;
1945 __u32 capabilities;
1946 __u16 count;
1947
1948 cFYI(1, ("In sesssetup "));
1949 if(ses == NULL)
1950 return -EINVAL;
1951 user = ses->userName;
1952 domain = ses->domainName;
1953 smb_buffer = cifs_buf_get();
1954 if (smb_buffer == NULL) {
1955 return -ENOMEM;
1956 }
1957 smb_buffer_response = smb_buffer;
1958 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1959
1960 /* send SMBsessionSetup here */
1961 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1962 NULL /* no tCon exists yet */ , 13 /* wct */ );
1963
Steve French1982c342005-08-17 12:38:22 -07001964 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 pSMB->req_no_secext.AndXCommand = 0xFF;
1966 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1967 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1968
1969 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1970 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1971
1972 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1973 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1974 if (ses->capabilities & CAP_UNICODE) {
1975 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1976 capabilities |= CAP_UNICODE;
1977 }
1978 if (ses->capabilities & CAP_STATUS32) {
1979 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1980 capabilities |= CAP_STATUS32;
1981 }
1982 if (ses->capabilities & CAP_DFS) {
1983 smb_buffer->Flags2 |= SMBFLG2_DFS;
1984 capabilities |= CAP_DFS;
1985 }
1986 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1987
1988 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1989 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1990
1991 pSMB->req_no_secext.CaseSensitivePasswordLength =
1992 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1993 bcc_ptr = pByteArea(smb_buffer);
1994 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1995 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1996 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1997 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1998
1999 if (ses->capabilities & CAP_UNICODE) {
2000 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2001 *bcc_ptr = 0;
2002 bcc_ptr++;
2003 }
2004 if(user == NULL)
2005 bytes_returned = 0; /* skill null user */
2006 else
2007 bytes_returned =
2008 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
2009 nls_codepage);
2010 /* convert number of 16 bit words to bytes */
2011 bcc_ptr += 2 * bytes_returned;
2012 bcc_ptr += 2; /* trailing null */
2013 if (domain == NULL)
2014 bytes_returned =
2015 cifs_strtoUCS((wchar_t *) bcc_ptr,
2016 "CIFS_LINUX_DOM", 32, nls_codepage);
2017 else
2018 bytes_returned =
2019 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2020 nls_codepage);
2021 bcc_ptr += 2 * bytes_returned;
2022 bcc_ptr += 2;
2023 bytes_returned =
2024 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2025 32, nls_codepage);
2026 bcc_ptr += 2 * bytes_returned;
2027 bytes_returned =
2028 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
2029 32, nls_codepage);
2030 bcc_ptr += 2 * bytes_returned;
2031 bcc_ptr += 2;
2032 bytes_returned =
2033 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2034 64, nls_codepage);
2035 bcc_ptr += 2 * bytes_returned;
2036 bcc_ptr += 2;
2037 } else {
2038 if(user != NULL) {
2039 strncpy(bcc_ptr, user, 200);
2040 bcc_ptr += strnlen(user, 200);
2041 }
2042 *bcc_ptr = 0;
2043 bcc_ptr++;
2044 if (domain == NULL) {
2045 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2046 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2047 } else {
2048 strncpy(bcc_ptr, domain, 64);
2049 bcc_ptr += strnlen(domain, 64);
2050 *bcc_ptr = 0;
2051 bcc_ptr++;
2052 }
2053 strcpy(bcc_ptr, "Linux version ");
2054 bcc_ptr += strlen("Linux version ");
2055 strcpy(bcc_ptr, system_utsname.release);
2056 bcc_ptr += strlen(system_utsname.release) + 1;
2057 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2058 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2059 }
2060 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2061 smb_buffer->smb_buf_length += count;
2062 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2063
2064 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2065 &bytes_returned, 1);
2066 if (rc) {
2067/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2068 } else if ((smb_buffer_response->WordCount == 3)
2069 || (smb_buffer_response->WordCount == 4)) {
2070 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2071 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2072 if (action & GUEST_LOGIN)
2073 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2074 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2075 cFYI(1, ("UID = %d ", ses->Suid));
2076 /* response can have either 3 or 4 word count - Samba sends 3 */
2077 bcc_ptr = pByteArea(smb_buffer_response);
2078 if ((pSMBr->resp.hdr.WordCount == 3)
2079 || ((pSMBr->resp.hdr.WordCount == 4)
2080 && (blob_len < pSMBr->resp.ByteCount))) {
2081 if (pSMBr->resp.hdr.WordCount == 4)
2082 bcc_ptr += blob_len;
2083
2084 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2085 if ((long) (bcc_ptr) % 2) {
2086 remaining_words =
2087 (BCC(smb_buffer_response) - 1) /2;
2088 bcc_ptr++; /* Unicode strings must be word aligned */
2089 } else {
2090 remaining_words =
2091 BCC(smb_buffer_response) / 2;
2092 }
2093 len =
2094 UniStrnlen((wchar_t *) bcc_ptr,
2095 remaining_words - 1);
2096/* We look for obvious messed up bcc or strings in response so we do not go off
2097 the end since (at least) WIN2K and Windows XP have a major bug in not null
2098 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07002099 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2100 if(ses->serverOS == NULL)
2101 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 cifs_strfromUCS_le(ses->serverOS,
2103 (wchar_t *)bcc_ptr, len,nls_codepage);
2104 bcc_ptr += 2 * (len + 1);
2105 remaining_words -= len + 1;
2106 ses->serverOS[2 * len] = 0;
2107 ses->serverOS[1 + (2 * len)] = 0;
2108 if (remaining_words > 0) {
2109 len = UniStrnlen((wchar_t *)bcc_ptr,
2110 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07002111 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2112 if(ses->serverNOS == NULL)
2113 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 cifs_strfromUCS_le(ses->serverNOS,
2115 (wchar_t *)bcc_ptr,len,nls_codepage);
2116 bcc_ptr += 2 * (len + 1);
2117 ses->serverNOS[2 * len] = 0;
2118 ses->serverNOS[1 + (2 * len)] = 0;
2119 if(strncmp(ses->serverNOS,
2120 "NT LAN Manager 4",16) == 0) {
2121 cFYI(1,("NT4 server"));
2122 ses->flags |= CIFS_SES_NT4;
2123 }
2124 remaining_words -= len + 1;
2125 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002126 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2128 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002129 kcalloc(1, 2*(len+1),GFP_KERNEL);
2130 if(ses->serverDomain == NULL)
2131 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 cifs_strfromUCS_le(ses->serverDomain,
2133 (wchar_t *)bcc_ptr,len,nls_codepage);
2134 bcc_ptr += 2 * (len + 1);
2135 ses->serverDomain[2*len] = 0;
2136 ses->serverDomain[1+(2*len)] = 0;
2137 } /* else no more room so create dummy domain string */
2138 else
Steve French433dc242005-04-28 22:41:08 -07002139 ses->serverDomain =
2140 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002142 /* if these kcallocs fail not much we
2143 can do, but better to not fail the
2144 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002146 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002148 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 }
2150 } else { /* ASCII */
2151 len = strnlen(bcc_ptr, 1024);
2152 if (((long) bcc_ptr + len) - (long)
2153 pByteArea(smb_buffer_response)
2154 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002155 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2156 if(ses->serverOS == NULL)
2157 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 strncpy(ses->serverOS,bcc_ptr, len);
2159
2160 bcc_ptr += len;
2161 bcc_ptr[0] = 0; /* null terminate the string */
2162 bcc_ptr++;
2163
2164 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002165 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2166 if(ses->serverNOS == NULL)
2167 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 strncpy(ses->serverNOS, bcc_ptr, len);
2169 bcc_ptr += len;
2170 bcc_ptr[0] = 0;
2171 bcc_ptr++;
2172
2173 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002174 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2175 if(ses->serverDomain == NULL)
2176 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 strncpy(ses->serverDomain, bcc_ptr, len);
2178 bcc_ptr += len;
2179 bcc_ptr[0] = 0;
2180 bcc_ptr++;
2181 } else
2182 cFYI(1,
2183 ("Variable field of length %d extends beyond end of smb ",
2184 len));
2185 }
2186 } else {
2187 cERROR(1,
2188 (" Security Blob Length extends beyond end of SMB"));
2189 }
2190 } else {
2191 cERROR(1,
2192 (" Invalid Word count %d: ",
2193 smb_buffer_response->WordCount));
2194 rc = -EIO;
2195 }
Steve French433dc242005-04-28 22:41:08 -07002196sesssetup_nomem: /* do not return an error on nomem for the info strings,
2197 since that could make reconnection harder, and
2198 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 if (smb_buffer)
2200 cifs_buf_release(smb_buffer);
2201
2202 return rc;
2203}
2204
2205static int
2206CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2207 char *SecurityBlob,int SecurityBlobLength,
2208 const struct nls_table *nls_codepage)
2209{
2210 struct smb_hdr *smb_buffer;
2211 struct smb_hdr *smb_buffer_response;
2212 SESSION_SETUP_ANDX *pSMB;
2213 SESSION_SETUP_ANDX *pSMBr;
2214 char *bcc_ptr;
2215 char *user;
2216 char *domain;
2217 int rc = 0;
2218 int remaining_words = 0;
2219 int bytes_returned = 0;
2220 int len;
2221 __u32 capabilities;
2222 __u16 count;
2223
2224 cFYI(1, ("In spnego sesssetup "));
2225 if(ses == NULL)
2226 return -EINVAL;
2227 user = ses->userName;
2228 domain = ses->domainName;
2229
2230 smb_buffer = cifs_buf_get();
2231 if (smb_buffer == NULL) {
2232 return -ENOMEM;
2233 }
2234 smb_buffer_response = smb_buffer;
2235 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2236
2237 /* send SMBsessionSetup here */
2238 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2239 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002240
2241 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2243 pSMB->req.AndXCommand = 0xFF;
2244 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2245 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2246
2247 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2248 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2249
2250 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2251 CAP_EXTENDED_SECURITY;
2252 if (ses->capabilities & CAP_UNICODE) {
2253 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2254 capabilities |= CAP_UNICODE;
2255 }
2256 if (ses->capabilities & CAP_STATUS32) {
2257 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2258 capabilities |= CAP_STATUS32;
2259 }
2260 if (ses->capabilities & CAP_DFS) {
2261 smb_buffer->Flags2 |= SMBFLG2_DFS;
2262 capabilities |= CAP_DFS;
2263 }
2264 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2265
2266 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2267 bcc_ptr = pByteArea(smb_buffer);
2268 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2269 bcc_ptr += SecurityBlobLength;
2270
2271 if (ses->capabilities & CAP_UNICODE) {
2272 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2273 *bcc_ptr = 0;
2274 bcc_ptr++;
2275 }
2276 bytes_returned =
2277 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2278 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2279 bcc_ptr += 2; /* trailing null */
2280 if (domain == NULL)
2281 bytes_returned =
2282 cifs_strtoUCS((wchar_t *) bcc_ptr,
2283 "CIFS_LINUX_DOM", 32, nls_codepage);
2284 else
2285 bytes_returned =
2286 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2287 nls_codepage);
2288 bcc_ptr += 2 * bytes_returned;
2289 bcc_ptr += 2;
2290 bytes_returned =
2291 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2292 32, nls_codepage);
2293 bcc_ptr += 2 * bytes_returned;
2294 bytes_returned =
2295 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2296 nls_codepage);
2297 bcc_ptr += 2 * bytes_returned;
2298 bcc_ptr += 2;
2299 bytes_returned =
2300 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2301 64, nls_codepage);
2302 bcc_ptr += 2 * bytes_returned;
2303 bcc_ptr += 2;
2304 } else {
2305 strncpy(bcc_ptr, user, 200);
2306 bcc_ptr += strnlen(user, 200);
2307 *bcc_ptr = 0;
2308 bcc_ptr++;
2309 if (domain == NULL) {
2310 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2311 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2312 } else {
2313 strncpy(bcc_ptr, domain, 64);
2314 bcc_ptr += strnlen(domain, 64);
2315 *bcc_ptr = 0;
2316 bcc_ptr++;
2317 }
2318 strcpy(bcc_ptr, "Linux version ");
2319 bcc_ptr += strlen("Linux version ");
2320 strcpy(bcc_ptr, system_utsname.release);
2321 bcc_ptr += strlen(system_utsname.release) + 1;
2322 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2323 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2324 }
2325 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2326 smb_buffer->smb_buf_length += count;
2327 pSMB->req.ByteCount = cpu_to_le16(count);
2328
2329 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2330 &bytes_returned, 1);
2331 if (rc) {
2332/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2333 } else if ((smb_buffer_response->WordCount == 3)
2334 || (smb_buffer_response->WordCount == 4)) {
2335 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2336 __u16 blob_len =
2337 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2338 if (action & GUEST_LOGIN)
2339 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2340 if (ses) {
2341 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2342 cFYI(1, ("UID = %d ", ses->Suid));
2343 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2344
2345 /* BB Fix below to make endian neutral !! */
2346
2347 if ((pSMBr->resp.hdr.WordCount == 3)
2348 || ((pSMBr->resp.hdr.WordCount == 4)
2349 && (blob_len <
2350 pSMBr->resp.ByteCount))) {
2351 if (pSMBr->resp.hdr.WordCount == 4) {
2352 bcc_ptr +=
2353 blob_len;
2354 cFYI(1,
2355 ("Security Blob Length %d ",
2356 blob_len));
2357 }
2358
2359 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2360 if ((long) (bcc_ptr) % 2) {
2361 remaining_words =
2362 (BCC(smb_buffer_response)
2363 - 1) / 2;
2364 bcc_ptr++; /* Unicode strings must be word aligned */
2365 } else {
2366 remaining_words =
2367 BCC
2368 (smb_buffer_response) / 2;
2369 }
2370 len =
2371 UniStrnlen((wchar_t *) bcc_ptr,
2372 remaining_words - 1);
2373/* We look for obvious messed up bcc or strings in response so we do not go off
2374 the end since (at least) WIN2K and Windows XP have a major bug in not null
2375 terminating last Unicode string in response */
2376 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002377 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 cifs_strfromUCS_le(ses->serverOS,
2379 (wchar_t *)
2380 bcc_ptr, len,
2381 nls_codepage);
2382 bcc_ptr += 2 * (len + 1);
2383 remaining_words -= len + 1;
2384 ses->serverOS[2 * len] = 0;
2385 ses->serverOS[1 + (2 * len)] = 0;
2386 if (remaining_words > 0) {
2387 len = UniStrnlen((wchar_t *)bcc_ptr,
2388 remaining_words
2389 - 1);
2390 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002391 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 GFP_KERNEL);
2393 cifs_strfromUCS_le(ses->serverNOS,
2394 (wchar_t *)bcc_ptr,
2395 len,
2396 nls_codepage);
2397 bcc_ptr += 2 * (len + 1);
2398 ses->serverNOS[2 * len] = 0;
2399 ses->serverNOS[1 + (2 * len)] = 0;
2400 remaining_words -= len + 1;
2401 if (remaining_words > 0) {
2402 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2403 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002404 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 cifs_strfromUCS_le(ses->serverDomain,
2406 (wchar_t *)bcc_ptr,
2407 len,
2408 nls_codepage);
2409 bcc_ptr += 2*(len+1);
2410 ses->serverDomain[2*len] = 0;
2411 ses->serverDomain[1+(2*len)] = 0;
2412 } /* else no more room so create dummy domain string */
2413 else
2414 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002415 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002417 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2418 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 }
2420 } else { /* ASCII */
2421
2422 len = strnlen(bcc_ptr, 1024);
2423 if (((long) bcc_ptr + len) - (long)
2424 pByteArea(smb_buffer_response)
2425 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002426 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 strncpy(ses->serverOS, bcc_ptr, len);
2428
2429 bcc_ptr += len;
2430 bcc_ptr[0] = 0; /* null terminate the string */
2431 bcc_ptr++;
2432
2433 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002434 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 strncpy(ses->serverNOS, bcc_ptr, len);
2436 bcc_ptr += len;
2437 bcc_ptr[0] = 0;
2438 bcc_ptr++;
2439
2440 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002441 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 strncpy(ses->serverDomain, bcc_ptr, len);
2443 bcc_ptr += len;
2444 bcc_ptr[0] = 0;
2445 bcc_ptr++;
2446 } else
2447 cFYI(1,
2448 ("Variable field of length %d extends beyond end of smb ",
2449 len));
2450 }
2451 } else {
2452 cERROR(1,
2453 (" Security Blob Length extends beyond end of SMB"));
2454 }
2455 } else {
2456 cERROR(1, ("No session structure passed in."));
2457 }
2458 } else {
2459 cERROR(1,
2460 (" Invalid Word count %d: ",
2461 smb_buffer_response->WordCount));
2462 rc = -EIO;
2463 }
2464
2465 if (smb_buffer)
2466 cifs_buf_release(smb_buffer);
2467
2468 return rc;
2469}
2470
2471static int
2472CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2473 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2474 const struct nls_table *nls_codepage)
2475{
2476 struct smb_hdr *smb_buffer;
2477 struct smb_hdr *smb_buffer_response;
2478 SESSION_SETUP_ANDX *pSMB;
2479 SESSION_SETUP_ANDX *pSMBr;
2480 char *bcc_ptr;
2481 char *domain;
2482 int rc = 0;
2483 int remaining_words = 0;
2484 int bytes_returned = 0;
2485 int len;
2486 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2487 PNEGOTIATE_MESSAGE SecurityBlob;
2488 PCHALLENGE_MESSAGE SecurityBlob2;
2489 __u32 negotiate_flags, capabilities;
2490 __u16 count;
2491
2492 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2493 if(ses == NULL)
2494 return -EINVAL;
2495 domain = ses->domainName;
2496 *pNTLMv2_flag = FALSE;
2497 smb_buffer = cifs_buf_get();
2498 if (smb_buffer == NULL) {
2499 return -ENOMEM;
2500 }
2501 smb_buffer_response = smb_buffer;
2502 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2503 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2504
2505 /* send SMBsessionSetup here */
2506 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2507 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002508
2509 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2511 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2512
2513 pSMB->req.AndXCommand = 0xFF;
2514 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2515 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2516
2517 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2518 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2519
2520 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2521 CAP_EXTENDED_SECURITY;
2522 if (ses->capabilities & CAP_UNICODE) {
2523 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2524 capabilities |= CAP_UNICODE;
2525 }
2526 if (ses->capabilities & CAP_STATUS32) {
2527 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2528 capabilities |= CAP_STATUS32;
2529 }
2530 if (ses->capabilities & CAP_DFS) {
2531 smb_buffer->Flags2 |= SMBFLG2_DFS;
2532 capabilities |= CAP_DFS;
2533 }
2534 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2535
2536 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2537 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2538 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2539 SecurityBlob->MessageType = NtLmNegotiate;
2540 negotiate_flags =
2541 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2542 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2543 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2544 if(sign_CIFS_PDUs)
2545 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2546 if(ntlmv2_support)
2547 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2548 /* setup pointers to domain name and workstation name */
2549 bcc_ptr += SecurityBlobLength;
2550
2551 SecurityBlob->WorkstationName.Buffer = 0;
2552 SecurityBlob->WorkstationName.Length = 0;
2553 SecurityBlob->WorkstationName.MaximumLength = 0;
2554
2555 if (domain == NULL) {
2556 SecurityBlob->DomainName.Buffer = 0;
2557 SecurityBlob->DomainName.Length = 0;
2558 SecurityBlob->DomainName.MaximumLength = 0;
2559 } else {
2560 __u16 len;
2561 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2562 strncpy(bcc_ptr, domain, 63);
2563 len = strnlen(domain, 64);
2564 SecurityBlob->DomainName.MaximumLength =
2565 cpu_to_le16(len);
2566 SecurityBlob->DomainName.Buffer =
2567 cpu_to_le32((long) &SecurityBlob->
2568 DomainString -
2569 (long) &SecurityBlob->Signature);
2570 bcc_ptr += len;
2571 SecurityBlobLength += len;
2572 SecurityBlob->DomainName.Length =
2573 cpu_to_le16(len);
2574 }
2575 if (ses->capabilities & CAP_UNICODE) {
2576 if ((long) bcc_ptr % 2) {
2577 *bcc_ptr = 0;
2578 bcc_ptr++;
2579 }
2580
2581 bytes_returned =
2582 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2583 32, nls_codepage);
2584 bcc_ptr += 2 * bytes_returned;
2585 bytes_returned =
2586 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2587 nls_codepage);
2588 bcc_ptr += 2 * bytes_returned;
2589 bcc_ptr += 2; /* null terminate Linux version */
2590 bytes_returned =
2591 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2592 64, nls_codepage);
2593 bcc_ptr += 2 * bytes_returned;
2594 *(bcc_ptr + 1) = 0;
2595 *(bcc_ptr + 2) = 0;
2596 bcc_ptr += 2; /* null terminate network opsys string */
2597 *(bcc_ptr + 1) = 0;
2598 *(bcc_ptr + 2) = 0;
2599 bcc_ptr += 2; /* null domain */
2600 } else { /* ASCII */
2601 strcpy(bcc_ptr, "Linux version ");
2602 bcc_ptr += strlen("Linux version ");
2603 strcpy(bcc_ptr, system_utsname.release);
2604 bcc_ptr += strlen(system_utsname.release) + 1;
2605 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2606 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2607 bcc_ptr++; /* empty domain field */
2608 *bcc_ptr = 0;
2609 }
2610 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2611 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2612 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2613 smb_buffer->smb_buf_length += count;
2614 pSMB->req.ByteCount = cpu_to_le16(count);
2615
2616 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2617 &bytes_returned, 1);
2618
2619 if (smb_buffer_response->Status.CifsError ==
2620 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2621 rc = 0;
2622
2623 if (rc) {
2624/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2625 } else if ((smb_buffer_response->WordCount == 3)
2626 || (smb_buffer_response->WordCount == 4)) {
2627 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2628 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2629
2630 if (action & GUEST_LOGIN)
2631 cFYI(1, (" Guest login"));
2632 /* Do we want to set anything in SesInfo struct when guest login? */
2633
2634 bcc_ptr = pByteArea(smb_buffer_response);
2635 /* response can have either 3 or 4 word count - Samba sends 3 */
2636
2637 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2638 if (SecurityBlob2->MessageType != NtLmChallenge) {
2639 cFYI(1,
2640 ("Unexpected NTLMSSP message type received %d",
2641 SecurityBlob2->MessageType));
2642 } else if (ses) {
2643 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2644 cFYI(1, ("UID = %d ", ses->Suid));
2645 if ((pSMBr->resp.hdr.WordCount == 3)
2646 || ((pSMBr->resp.hdr.WordCount == 4)
2647 && (blob_len <
2648 pSMBr->resp.ByteCount))) {
2649
2650 if (pSMBr->resp.hdr.WordCount == 4) {
2651 bcc_ptr += blob_len;
2652 cFYI(1,
2653 ("Security Blob Length %d ",
2654 blob_len));
2655 }
2656
2657 cFYI(1, ("NTLMSSP Challenge rcvd "));
2658
2659 memcpy(ses->server->cryptKey,
2660 SecurityBlob2->Challenge,
2661 CIFS_CRYPTO_KEY_SIZE);
2662 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2663 *pNTLMv2_flag = TRUE;
2664
2665 if((SecurityBlob2->NegotiateFlags &
2666 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2667 || (sign_CIFS_PDUs > 1))
2668 ses->server->secMode |=
2669 SECMODE_SIGN_REQUIRED;
2670 if ((SecurityBlob2->NegotiateFlags &
2671 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2672 ses->server->secMode |=
2673 SECMODE_SIGN_ENABLED;
2674
2675 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2676 if ((long) (bcc_ptr) % 2) {
2677 remaining_words =
2678 (BCC(smb_buffer_response)
2679 - 1) / 2;
2680 bcc_ptr++; /* Unicode strings must be word aligned */
2681 } else {
2682 remaining_words =
2683 BCC
2684 (smb_buffer_response) / 2;
2685 }
2686 len =
2687 UniStrnlen((wchar_t *) bcc_ptr,
2688 remaining_words - 1);
2689/* We look for obvious messed up bcc or strings in response so we do not go off
2690 the end since (at least) WIN2K and Windows XP have a major bug in not null
2691 terminating last Unicode string in response */
2692 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002693 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 cifs_strfromUCS_le(ses->serverOS,
2695 (wchar_t *)
2696 bcc_ptr, len,
2697 nls_codepage);
2698 bcc_ptr += 2 * (len + 1);
2699 remaining_words -= len + 1;
2700 ses->serverOS[2 * len] = 0;
2701 ses->serverOS[1 + (2 * len)] = 0;
2702 if (remaining_words > 0) {
2703 len = UniStrnlen((wchar_t *)
2704 bcc_ptr,
2705 remaining_words
2706 - 1);
2707 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002708 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 GFP_KERNEL);
2710 cifs_strfromUCS_le(ses->
2711 serverNOS,
2712 (wchar_t *)
2713 bcc_ptr,
2714 len,
2715 nls_codepage);
2716 bcc_ptr += 2 * (len + 1);
2717 ses->serverNOS[2 * len] = 0;
2718 ses->serverNOS[1 +
2719 (2 * len)] = 0;
2720 remaining_words -= len + 1;
2721 if (remaining_words > 0) {
2722 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2723 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2724 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002725 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 (len +
2727 1),
2728 GFP_KERNEL);
2729 cifs_strfromUCS_le
2730 (ses->
2731 serverDomain,
2732 (wchar_t *)
2733 bcc_ptr, len,
2734 nls_codepage);
2735 bcc_ptr +=
2736 2 * (len + 1);
2737 ses->
2738 serverDomain[2
2739 * len]
2740 = 0;
2741 ses->
2742 serverDomain[1
2743 +
2744 (2
2745 *
2746 len)]
2747 = 0;
2748 } /* else no more room so create dummy domain string */
2749 else
2750 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002751 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 GFP_KERNEL);
2753 } else { /* no room so create dummy domain and NOS string */
2754 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002755 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002757 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 }
2759 } else { /* ASCII */
2760 len = strnlen(bcc_ptr, 1024);
2761 if (((long) bcc_ptr + len) - (long)
2762 pByteArea(smb_buffer_response)
2763 <= BCC(smb_buffer_response)) {
2764 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002765 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 GFP_KERNEL);
2767 strncpy(ses->serverOS,
2768 bcc_ptr, len);
2769
2770 bcc_ptr += len;
2771 bcc_ptr[0] = 0; /* null terminate string */
2772 bcc_ptr++;
2773
2774 len = strnlen(bcc_ptr, 1024);
2775 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002776 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 GFP_KERNEL);
2778 strncpy(ses->serverNOS, bcc_ptr, len);
2779 bcc_ptr += len;
2780 bcc_ptr[0] = 0;
2781 bcc_ptr++;
2782
2783 len = strnlen(bcc_ptr, 1024);
2784 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002785 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 GFP_KERNEL);
2787 strncpy(ses->serverDomain, bcc_ptr, len);
2788 bcc_ptr += len;
2789 bcc_ptr[0] = 0;
2790 bcc_ptr++;
2791 } else
2792 cFYI(1,
2793 ("Variable field of length %d extends beyond end of smb ",
2794 len));
2795 }
2796 } else {
2797 cERROR(1,
2798 (" Security Blob Length extends beyond end of SMB"));
2799 }
2800 } else {
2801 cERROR(1, ("No session structure passed in."));
2802 }
2803 } else {
2804 cERROR(1,
2805 (" Invalid Word count %d: ",
2806 smb_buffer_response->WordCount));
2807 rc = -EIO;
2808 }
2809
2810 if (smb_buffer)
2811 cifs_buf_release(smb_buffer);
2812
2813 return rc;
2814}
2815static int
2816CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2817 char *ntlm_session_key, int ntlmv2_flag,
2818 const struct nls_table *nls_codepage)
2819{
2820 struct smb_hdr *smb_buffer;
2821 struct smb_hdr *smb_buffer_response;
2822 SESSION_SETUP_ANDX *pSMB;
2823 SESSION_SETUP_ANDX *pSMBr;
2824 char *bcc_ptr;
2825 char *user;
2826 char *domain;
2827 int rc = 0;
2828 int remaining_words = 0;
2829 int bytes_returned = 0;
2830 int len;
2831 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2832 PAUTHENTICATE_MESSAGE SecurityBlob;
2833 __u32 negotiate_flags, capabilities;
2834 __u16 count;
2835
2836 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2837 if(ses == NULL)
2838 return -EINVAL;
2839 user = ses->userName;
2840 domain = ses->domainName;
2841 smb_buffer = cifs_buf_get();
2842 if (smb_buffer == NULL) {
2843 return -ENOMEM;
2844 }
2845 smb_buffer_response = smb_buffer;
2846 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2847 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2848
2849 /* send SMBsessionSetup here */
2850 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2851 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002852
2853 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2855 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2856 pSMB->req.AndXCommand = 0xFF;
2857 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2858 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2859
2860 pSMB->req.hdr.Uid = ses->Suid;
2861
2862 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2863 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2864
2865 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2866 CAP_EXTENDED_SECURITY;
2867 if (ses->capabilities & CAP_UNICODE) {
2868 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2869 capabilities |= CAP_UNICODE;
2870 }
2871 if (ses->capabilities & CAP_STATUS32) {
2872 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2873 capabilities |= CAP_STATUS32;
2874 }
2875 if (ses->capabilities & CAP_DFS) {
2876 smb_buffer->Flags2 |= SMBFLG2_DFS;
2877 capabilities |= CAP_DFS;
2878 }
2879 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2880
2881 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2882 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2883 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2884 SecurityBlob->MessageType = NtLmAuthenticate;
2885 bcc_ptr += SecurityBlobLength;
2886 negotiate_flags =
2887 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2888 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2889 0x80000000 | NTLMSSP_NEGOTIATE_128;
2890 if(sign_CIFS_PDUs)
2891 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2892 if(ntlmv2_flag)
2893 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2894
2895/* setup pointers to domain name and workstation name */
2896
2897 SecurityBlob->WorkstationName.Buffer = 0;
2898 SecurityBlob->WorkstationName.Length = 0;
2899 SecurityBlob->WorkstationName.MaximumLength = 0;
2900 SecurityBlob->SessionKey.Length = 0;
2901 SecurityBlob->SessionKey.MaximumLength = 0;
2902 SecurityBlob->SessionKey.Buffer = 0;
2903
2904 SecurityBlob->LmChallengeResponse.Length = 0;
2905 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2906 SecurityBlob->LmChallengeResponse.Buffer = 0;
2907
2908 SecurityBlob->NtChallengeResponse.Length =
2909 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2910 SecurityBlob->NtChallengeResponse.MaximumLength =
2911 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2912 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2913 SecurityBlob->NtChallengeResponse.Buffer =
2914 cpu_to_le32(SecurityBlobLength);
2915 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2916 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2917
2918 if (ses->capabilities & CAP_UNICODE) {
2919 if (domain == NULL) {
2920 SecurityBlob->DomainName.Buffer = 0;
2921 SecurityBlob->DomainName.Length = 0;
2922 SecurityBlob->DomainName.MaximumLength = 0;
2923 } else {
2924 __u16 len =
2925 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2926 nls_codepage);
2927 len *= 2;
2928 SecurityBlob->DomainName.MaximumLength =
2929 cpu_to_le16(len);
2930 SecurityBlob->DomainName.Buffer =
2931 cpu_to_le32(SecurityBlobLength);
2932 bcc_ptr += len;
2933 SecurityBlobLength += len;
2934 SecurityBlob->DomainName.Length =
2935 cpu_to_le16(len);
2936 }
2937 if (user == NULL) {
2938 SecurityBlob->UserName.Buffer = 0;
2939 SecurityBlob->UserName.Length = 0;
2940 SecurityBlob->UserName.MaximumLength = 0;
2941 } else {
2942 __u16 len =
2943 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2944 nls_codepage);
2945 len *= 2;
2946 SecurityBlob->UserName.MaximumLength =
2947 cpu_to_le16(len);
2948 SecurityBlob->UserName.Buffer =
2949 cpu_to_le32(SecurityBlobLength);
2950 bcc_ptr += len;
2951 SecurityBlobLength += len;
2952 SecurityBlob->UserName.Length =
2953 cpu_to_le16(len);
2954 }
2955
2956 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2957 SecurityBlob->WorkstationName.Length *= 2;
2958 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2959 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2960 bcc_ptr += SecurityBlob->WorkstationName.Length;
2961 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2962 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2963
2964 if ((long) bcc_ptr % 2) {
2965 *bcc_ptr = 0;
2966 bcc_ptr++;
2967 }
2968 bytes_returned =
2969 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2970 32, nls_codepage);
2971 bcc_ptr += 2 * bytes_returned;
2972 bytes_returned =
2973 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2974 nls_codepage);
2975 bcc_ptr += 2 * bytes_returned;
2976 bcc_ptr += 2; /* null term version string */
2977 bytes_returned =
2978 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2979 64, nls_codepage);
2980 bcc_ptr += 2 * bytes_returned;
2981 *(bcc_ptr + 1) = 0;
2982 *(bcc_ptr + 2) = 0;
2983 bcc_ptr += 2; /* null terminate network opsys string */
2984 *(bcc_ptr + 1) = 0;
2985 *(bcc_ptr + 2) = 0;
2986 bcc_ptr += 2; /* null domain */
2987 } else { /* ASCII */
2988 if (domain == NULL) {
2989 SecurityBlob->DomainName.Buffer = 0;
2990 SecurityBlob->DomainName.Length = 0;
2991 SecurityBlob->DomainName.MaximumLength = 0;
2992 } else {
2993 __u16 len;
2994 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2995 strncpy(bcc_ptr, domain, 63);
2996 len = strnlen(domain, 64);
2997 SecurityBlob->DomainName.MaximumLength =
2998 cpu_to_le16(len);
2999 SecurityBlob->DomainName.Buffer =
3000 cpu_to_le32(SecurityBlobLength);
3001 bcc_ptr += len;
3002 SecurityBlobLength += len;
3003 SecurityBlob->DomainName.Length = cpu_to_le16(len);
3004 }
3005 if (user == NULL) {
3006 SecurityBlob->UserName.Buffer = 0;
3007 SecurityBlob->UserName.Length = 0;
3008 SecurityBlob->UserName.MaximumLength = 0;
3009 } else {
3010 __u16 len;
3011 strncpy(bcc_ptr, user, 63);
3012 len = strnlen(user, 64);
3013 SecurityBlob->UserName.MaximumLength =
3014 cpu_to_le16(len);
3015 SecurityBlob->UserName.Buffer =
3016 cpu_to_le32(SecurityBlobLength);
3017 bcc_ptr += len;
3018 SecurityBlobLength += len;
3019 SecurityBlob->UserName.Length = cpu_to_le16(len);
3020 }
3021 /* BB fill in our workstation name if known BB */
3022
3023 strcpy(bcc_ptr, "Linux version ");
3024 bcc_ptr += strlen("Linux version ");
3025 strcpy(bcc_ptr, system_utsname.release);
3026 bcc_ptr += strlen(system_utsname.release) + 1;
3027 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3028 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3029 bcc_ptr++; /* null domain */
3030 *bcc_ptr = 0;
3031 }
3032 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3033 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3034 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3035 smb_buffer->smb_buf_length += count;
3036 pSMB->req.ByteCount = cpu_to_le16(count);
3037
3038 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3039 &bytes_returned, 1);
3040 if (rc) {
3041/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3042 } else if ((smb_buffer_response->WordCount == 3)
3043 || (smb_buffer_response->WordCount == 4)) {
3044 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3045 __u16 blob_len =
3046 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3047 if (action & GUEST_LOGIN)
3048 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3049/* if(SecurityBlob2->MessageType != NtLm??){
3050 cFYI("Unexpected message type on auth response is %d "));
3051 } */
3052 if (ses) {
3053 cFYI(1,
3054 ("Does UID on challenge %d match auth response UID %d ",
3055 ses->Suid, smb_buffer_response->Uid));
3056 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3057 bcc_ptr = pByteArea(smb_buffer_response);
3058 /* response can have either 3 or 4 word count - Samba sends 3 */
3059 if ((pSMBr->resp.hdr.WordCount == 3)
3060 || ((pSMBr->resp.hdr.WordCount == 4)
3061 && (blob_len <
3062 pSMBr->resp.ByteCount))) {
3063 if (pSMBr->resp.hdr.WordCount == 4) {
3064 bcc_ptr +=
3065 blob_len;
3066 cFYI(1,
3067 ("Security Blob Length %d ",
3068 blob_len));
3069 }
3070
3071 cFYI(1,
3072 ("NTLMSSP response to Authenticate "));
3073
3074 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3075 if ((long) (bcc_ptr) % 2) {
3076 remaining_words =
3077 (BCC(smb_buffer_response)
3078 - 1) / 2;
3079 bcc_ptr++; /* Unicode strings must be word aligned */
3080 } else {
3081 remaining_words = BCC(smb_buffer_response) / 2;
3082 }
3083 len =
3084 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3085/* We look for obvious messed up bcc or strings in response so we do not go off
3086 the end since (at least) WIN2K and Windows XP have a major bug in not null
3087 terminating last Unicode string in response */
3088 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07003089 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 cifs_strfromUCS_le(ses->serverOS,
3091 (wchar_t *)
3092 bcc_ptr, len,
3093 nls_codepage);
3094 bcc_ptr += 2 * (len + 1);
3095 remaining_words -= len + 1;
3096 ses->serverOS[2 * len] = 0;
3097 ses->serverOS[1 + (2 * len)] = 0;
3098 if (remaining_words > 0) {
3099 len = UniStrnlen((wchar_t *)
3100 bcc_ptr,
3101 remaining_words
3102 - 1);
3103 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07003104 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 GFP_KERNEL);
3106 cifs_strfromUCS_le(ses->
3107 serverNOS,
3108 (wchar_t *)
3109 bcc_ptr,
3110 len,
3111 nls_codepage);
3112 bcc_ptr += 2 * (len + 1);
3113 ses->serverNOS[2 * len] = 0;
3114 ses->serverNOS[1+(2*len)] = 0;
3115 remaining_words -= len + 1;
3116 if (remaining_words > 0) {
3117 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3118 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3119 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07003120 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 (len +
3122 1),
3123 GFP_KERNEL);
3124 cifs_strfromUCS_le
3125 (ses->
3126 serverDomain,
3127 (wchar_t *)
3128 bcc_ptr, len,
3129 nls_codepage);
3130 bcc_ptr +=
3131 2 * (len + 1);
3132 ses->
3133 serverDomain[2
3134 * len]
3135 = 0;
3136 ses->
3137 serverDomain[1
3138 +
3139 (2
3140 *
3141 len)]
3142 = 0;
3143 } /* else no more room so create dummy domain string */
3144 else
Steve French433dc242005-04-28 22:41:08 -07003145 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07003147 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3148 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 }
3150 } else { /* ASCII */
3151 len = strnlen(bcc_ptr, 1024);
3152 if (((long) bcc_ptr + len) -
3153 (long) pByteArea(smb_buffer_response)
3154 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07003155 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 strncpy(ses->serverOS,bcc_ptr, len);
3157
3158 bcc_ptr += len;
3159 bcc_ptr[0] = 0; /* null terminate the string */
3160 bcc_ptr++;
3161
3162 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003163 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 strncpy(ses->serverNOS, bcc_ptr, len);
3165 bcc_ptr += len;
3166 bcc_ptr[0] = 0;
3167 bcc_ptr++;
3168
3169 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003170 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 strncpy(ses->serverDomain, bcc_ptr, len);
3172 bcc_ptr += len;
3173 bcc_ptr[0] = 0;
3174 bcc_ptr++;
3175 } else
3176 cFYI(1,
3177 ("Variable field of length %d extends beyond end of smb ",
3178 len));
3179 }
3180 } else {
3181 cERROR(1,
3182 (" Security Blob Length extends beyond end of SMB"));
3183 }
3184 } else {
3185 cERROR(1, ("No session structure passed in."));
3186 }
3187 } else {
3188 cERROR(1,
3189 (" Invalid Word count %d: ",
3190 smb_buffer_response->WordCount));
3191 rc = -EIO;
3192 }
3193
3194 if (smb_buffer)
3195 cifs_buf_release(smb_buffer);
3196
3197 return rc;
3198}
3199
3200int
3201CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3202 const char *tree, struct cifsTconInfo *tcon,
3203 const struct nls_table *nls_codepage)
3204{
3205 struct smb_hdr *smb_buffer;
3206 struct smb_hdr *smb_buffer_response;
3207 TCONX_REQ *pSMB;
3208 TCONX_RSP *pSMBr;
3209 unsigned char *bcc_ptr;
3210 int rc = 0;
3211 int length;
3212 __u16 count;
3213
3214 if (ses == NULL)
3215 return -EIO;
3216
3217 smb_buffer = cifs_buf_get();
3218 if (smb_buffer == NULL) {
3219 return -ENOMEM;
3220 }
3221 smb_buffer_response = smb_buffer;
3222
3223 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3224 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003225
3226 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 smb_buffer->Uid = ses->Suid;
3228 pSMB = (TCONX_REQ *) smb_buffer;
3229 pSMBr = (TCONX_RSP *) smb_buffer_response;
3230
3231 pSMB->AndXCommand = 0xFF;
3232 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3233 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3234 bcc_ptr = &pSMB->Password[0];
3235 bcc_ptr++; /* skip password */
3236
3237 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3238 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3239
3240 if (ses->capabilities & CAP_STATUS32) {
3241 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3242 }
3243 if (ses->capabilities & CAP_DFS) {
3244 smb_buffer->Flags2 |= SMBFLG2_DFS;
3245 }
3246 if (ses->capabilities & CAP_UNICODE) {
3247 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3248 length =
3249 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3250 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3251 bcc_ptr += 2; /* skip trailing null */
3252 } else { /* ASCII */
3253
3254 strcpy(bcc_ptr, tree);
3255 bcc_ptr += strlen(tree) + 1;
3256 }
3257 strcpy(bcc_ptr, "?????");
3258 bcc_ptr += strlen("?????");
3259 bcc_ptr += 1;
3260 count = bcc_ptr - &pSMB->Password[0];
3261 pSMB->hdr.smb_buf_length += count;
3262 pSMB->ByteCount = cpu_to_le16(count);
3263
3264 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3265
3266 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3267 /* above now done in SendReceive */
3268 if ((rc == 0) && (tcon != NULL)) {
3269 tcon->tidStatus = CifsGood;
3270 tcon->tid = smb_buffer_response->Tid;
3271 bcc_ptr = pByteArea(smb_buffer_response);
3272 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3273 /* skip service field (NB: this field is always ASCII) */
3274 bcc_ptr += length + 1;
3275 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3276 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3277 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3278 if ((bcc_ptr + (2 * length)) -
3279 pByteArea(smb_buffer_response) <=
3280 BCC(smb_buffer_response)) {
3281 if(tcon->nativeFileSystem)
3282 kfree(tcon->nativeFileSystem);
3283 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003284 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 cifs_strfromUCS_le(tcon->nativeFileSystem,
3286 (wchar_t *) bcc_ptr,
3287 length, nls_codepage);
3288 bcc_ptr += 2 * length;
3289 bcc_ptr[0] = 0; /* null terminate the string */
3290 bcc_ptr[1] = 0;
3291 bcc_ptr += 2;
3292 }
3293 /* else do not bother copying these informational fields */
3294 } else {
3295 length = strnlen(bcc_ptr, 1024);
3296 if ((bcc_ptr + length) -
3297 pByteArea(smb_buffer_response) <=
3298 BCC(smb_buffer_response)) {
3299 if(tcon->nativeFileSystem)
3300 kfree(tcon->nativeFileSystem);
3301 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003302 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 strncpy(tcon->nativeFileSystem, bcc_ptr,
3304 length);
3305 }
3306 /* else do not bother copying these informational fields */
3307 }
3308 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3309 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3310 } else if ((rc == 0) && tcon == NULL) {
3311 /* all we need to save for IPC$ connection */
3312 ses->ipc_tid = smb_buffer_response->Tid;
3313 }
3314
3315 if (smb_buffer)
3316 cifs_buf_release(smb_buffer);
3317 return rc;
3318}
3319
3320int
3321cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3322{
3323 int rc = 0;
3324 int xid;
3325 struct cifsSesInfo *ses = NULL;
3326 struct task_struct *cifsd_task;
3327
3328 xid = GetXid();
3329
3330 if (cifs_sb->tcon) {
3331 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3332 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3333 if (rc == -EBUSY) {
3334 FreeXid(xid);
3335 return 0;
3336 }
3337 tconInfoFree(cifs_sb->tcon);
3338 if ((ses) && (ses->server)) {
3339 /* save off task so we do not refer to ses later */
3340 cifsd_task = ses->server->tsk;
3341 cFYI(1, ("About to do SMBLogoff "));
3342 rc = CIFSSMBLogoff(xid, ses);
3343 if (rc == -EBUSY) {
3344 FreeXid(xid);
3345 return 0;
3346 } else if (rc == -ESHUTDOWN) {
3347 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003348 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003350 wait_for_completion(&cifsd_complete);
3351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 rc = 0;
3353 } /* else - we have an smb session
3354 left on this socket do not kill cifsd */
3355 } else
3356 cFYI(1, ("No session or bad tcon"));
3357 }
3358
3359 cifs_sb->tcon = NULL;
3360 if (ses) {
3361 set_current_state(TASK_INTERRUPTIBLE);
3362 schedule_timeout(HZ / 2);
3363 }
3364 if (ses)
3365 sesInfoFree(ses);
3366
3367 FreeXid(xid);
3368 return rc; /* BB check if we should always return zero here */
3369}
3370
3371int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3372 struct nls_table * nls_info)
3373{
3374 int rc = 0;
3375 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3376 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003377 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378
3379 /* what if server changes its buffer size after dropping the session? */
3380 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3381 rc = CIFSSMBNegotiate(xid, pSesInfo);
3382 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3383 rc = CIFSSMBNegotiate(xid, pSesInfo);
3384 if(rc == -EAGAIN)
3385 rc = -EHOSTDOWN;
3386 }
3387 if(rc == 0) {
3388 spin_lock(&GlobalMid_Lock);
3389 if(pSesInfo->server->tcpStatus != CifsExiting)
3390 pSesInfo->server->tcpStatus = CifsGood;
3391 else
3392 rc = -EHOSTDOWN;
3393 spin_unlock(&GlobalMid_Lock);
3394
3395 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003396 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 }
3398 if (!rc) {
3399 pSesInfo->capabilities = pSesInfo->server->capabilities;
3400 if(linuxExtEnabled == 0)
3401 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003402 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3404 pSesInfo->server->secMode,
3405 pSesInfo->server->capabilities,
3406 pSesInfo->server->timeZone));
3407 if (extended_security
3408 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3409 && (pSesInfo->server->secType == NTLMSSP)) {
3410 cFYI(1, ("New style sesssetup "));
3411 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3412 NULL /* security blob */,
3413 0 /* blob length */,
3414 nls_info);
3415 } else if (extended_security
3416 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3417 && (pSesInfo->server->secType == RawNTLMSSP)) {
3418 cFYI(1, ("NTLMSSP sesssetup "));
3419 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3420 pSesInfo,
3421 &ntlmv2_flag,
3422 nls_info);
3423 if (!rc) {
3424 if(ntlmv2_flag) {
3425 char * v2_response;
3426 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3427 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3428 nls_info)) {
3429 rc = -ENOMEM;
3430 goto ss_err_exit;
3431 } else
3432 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3433 if(v2_response) {
3434 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003435 /* if(first_time)
3436 cifs_calculate_ntlmv2_mac_key(
3437 pSesInfo->server->mac_signing_key,
3438 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 kfree(v2_response);
3440 /* BB Put dummy sig in SessSetup PDU? */
3441 } else {
3442 rc = -ENOMEM;
3443 goto ss_err_exit;
3444 }
3445
3446 } else {
3447 SMBNTencrypt(pSesInfo->password,
3448 pSesInfo->server->cryptKey,
3449 ntlm_session_key);
3450
Steve Frenchad009ac2005-04-28 22:41:05 -07003451 if(first_time)
3452 cifs_calculate_mac_key(
3453 pSesInfo->server->mac_signing_key,
3454 ntlm_session_key,
3455 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 }
3457 /* for better security the weaker lanman hash not sent
3458 in AuthSessSetup so we no longer calculate it */
3459
3460 rc = CIFSNTLMSSPAuthSessSetup(xid,
3461 pSesInfo,
3462 ntlm_session_key,
3463 ntlmv2_flag,
3464 nls_info);
3465 }
3466 } else { /* old style NTLM 0.12 session setup */
3467 SMBNTencrypt(pSesInfo->password,
3468 pSesInfo->server->cryptKey,
3469 ntlm_session_key);
3470
Steve Frenchad009ac2005-04-28 22:41:05 -07003471 if(first_time)
3472 cifs_calculate_mac_key(
3473 pSesInfo->server->mac_signing_key,
3474 ntlm_session_key, pSesInfo->password);
3475
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 rc = CIFSSessSetup(xid, pSesInfo,
3477 ntlm_session_key, nls_info);
3478 }
3479 if (rc) {
3480 cERROR(1,("Send error in SessSetup = %d",rc));
3481 } else {
3482 cFYI(1,("CIFS Session Established successfully"));
3483 pSesInfo->status = CifsGood;
3484 }
3485 }
3486ss_err_exit:
3487 return rc;
3488}
3489