blob: 437be1efe99e2ac4a2047e43f660e94beaff39d3 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/uaccess.h>
33#include <asm/processor.h>
34#include "cifspdu.h"
35#include "cifsglob.h"
36#include "cifsproto.h"
37#include "cifs_unicode.h"
38#include "cifs_debug.h"
39#include "cifs_fs_sb.h"
40#include "ntlmssp.h"
41#include "nterr.h"
42#include "rfc1002pdu.h"
43
44#define CIFS_PORT 445
45#define RFC1001_PORT 139
46
47extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
48 unsigned char *p24);
49extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
50 unsigned char *p24);
51
52extern mempool_t *cifs_req_poolp;
53
54struct smb_vol {
55 char *username;
56 char *password;
57 char *domainname;
58 char *UNC;
59 char *UNCip;
60 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
61 char *iocharset; /* local code page for mapping to and from Unicode */
62 char source_rfc1001_name[16]; /* netbios name of client */
63 uid_t linux_uid;
64 gid_t linux_gid;
65 mode_t file_mode;
66 mode_t dir_mode;
67 unsigned rw:1;
68 unsigned retry:1;
69 unsigned intr:1;
70 unsigned setuids:1;
71 unsigned noperm:1;
72 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
73 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
74 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
75 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070076 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 unsigned int rsize;
78 unsigned int wsize;
79 unsigned int sockopt;
80 unsigned short int port;
81};
82
83static int ipv4_connect(struct sockaddr_in *psin_server,
84 struct socket **csocket,
85 char * netb_name);
86static int ipv6_connect(struct sockaddr_in6 *psin_server,
87 struct socket **csocket);
88
89
90 /*
91 * cifs tcp session reconnection
92 *
93 * mark tcp session as reconnecting so temporarily locked
94 * mark all smb sessions as reconnecting for tcp session
95 * reconnect tcp session
96 * wake up waiters on reconnection? - (not needed currently)
97 */
98
99int
100cifs_reconnect(struct TCP_Server_Info *server)
101{
102 int rc = 0;
103 struct list_head *tmp;
104 struct cifsSesInfo *ses;
105 struct cifsTconInfo *tcon;
106 struct mid_q_entry * mid_entry;
107
108 spin_lock(&GlobalMid_Lock);
109 if(server->tcpStatus == CifsExiting) {
110 /* the demux thread will exit normally
111 next time through the loop */
112 spin_unlock(&GlobalMid_Lock);
113 return rc;
114 } else
115 server->tcpStatus = CifsNeedReconnect;
116 spin_unlock(&GlobalMid_Lock);
117 server->maxBuf = 0;
118
Steve Frenche4eb2952005-04-28 22:41:09 -0700119 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121 /* before reconnecting the tcp session, mark the smb session (uid)
122 and the tid bad so they are not used until reconnected */
123 read_lock(&GlobalSMBSeslock);
124 list_for_each(tmp, &GlobalSMBSessionList) {
125 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
126 if (ses->server) {
127 if (ses->server == server) {
128 ses->status = CifsNeedReconnect;
129 ses->ipc_tid = 0;
130 }
131 }
132 /* else tcp and smb sessions need reconnection */
133 }
134 list_for_each(tmp, &GlobalTreeConnectionList) {
135 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
136 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
137 tcon->tidStatus = CifsNeedReconnect;
138 }
139 }
140 read_unlock(&GlobalSMBSeslock);
141 /* do not want to be sending data on a socket we are freeing */
142 down(&server->tcpSem);
143 if(server->ssocket) {
144 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
145 server->ssocket->flags));
146 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
147 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
148 server->ssocket->flags));
149 sock_release(server->ssocket);
150 server->ssocket = NULL;
151 }
152
153 spin_lock(&GlobalMid_Lock);
154 list_for_each(tmp, &server->pending_mid_q) {
155 mid_entry = list_entry(tmp, struct
156 mid_q_entry,
157 qhead);
158 if(mid_entry) {
159 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700160 /* Mark other intransit requests as needing
161 retry so we do not immediately mark the
162 session bad again (ie after we reconnect
163 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 mid_entry->midState = MID_RETRY_NEEDED;
165 }
166 }
167 }
168 spin_unlock(&GlobalMid_Lock);
169 up(&server->tcpSem);
170
171 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
172 {
173 if(server->protocolType == IPV6) {
174 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
175 } else {
176 rc = ipv4_connect(&server->addr.sockAddr,
177 &server->ssocket,
178 server->workstation_RFC1001_name);
179 }
180 if(rc) {
181 set_current_state(TASK_INTERRUPTIBLE);
182 schedule_timeout(3 * HZ);
183 } else {
184 atomic_inc(&tcpSesReconnectCount);
185 spin_lock(&GlobalMid_Lock);
186 if(server->tcpStatus != CifsExiting)
187 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700188 server->sequence_number = 0;
189 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 /* atomic_set(&server->inFlight,0);*/
191 wake_up(&server->response_q);
192 }
193 }
194 return rc;
195}
196
Steve Frenche4eb2952005-04-28 22:41:09 -0700197/*
198 return codes:
199 0 not a transact2, or all data present
200 >0 transact2 with that much data missing
201 -EINVAL = invalid transact2
202
203 */
204static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
205{
206 struct smb_t2_rsp * pSMBt;
207 int total_data_size;
208 int data_in_this_rsp;
209 int remaining;
210
211 if(pSMB->Command != SMB_COM_TRANSACTION2)
212 return 0;
213
214 /* check for plausible wct, bcc and t2 data and parm sizes */
215 /* check for parm and data offset going beyond end of smb */
216 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
217 cFYI(1,("invalid transact2 word count"));
218 return -EINVAL;
219 }
220
221 pSMBt = (struct smb_t2_rsp *)pSMB;
222
223 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
224 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
225
226 remaining = total_data_size - data_in_this_rsp;
227
228 if(remaining == 0)
229 return 0;
230 else if(remaining < 0) {
231 cFYI(1,("total data %d smaller than data in frame %d",
232 total_data_size, data_in_this_rsp));
233 return -EINVAL;
234 } else {
235 cFYI(1,("missing %d bytes from transact2, check next response",
236 remaining));
237 if(total_data_size > maxBufSize) {
238 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
239 total_data_size,maxBufSize));
240 return -EINVAL;
241 }
242 return remaining;
243 }
244}
245
246static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
247{
248 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
249 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
250 int total_data_size;
251 int total_in_buf;
252 int remaining;
253 int total_in_buf2;
254 char * data_area_of_target;
255 char * data_area_of_buf2;
256 __u16 byte_count;
257
258 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
259
260 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
261 cFYI(1,("total data sizes of primary and secondary t2 differ"));
262 }
263
264 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
265
266 remaining = total_data_size - total_in_buf;
267
268 if(remaining < 0)
269 return -EINVAL;
270
271 if(remaining == 0) /* nothing to do, ignore */
272 return 0;
273
274 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
275 if(remaining < total_in_buf2) {
276 cFYI(1,("transact2 2nd response contains too much data"));
277 }
278
279 /* find end of first SMB data area */
280 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
281 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
282 /* validate target area */
283
284 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
285 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
286
287 data_area_of_target += total_in_buf;
288
289 /* copy second buffer into end of first buffer */
290 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
291 total_in_buf += total_in_buf2;
292 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
293 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
294 byte_count += total_in_buf2;
295 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
296
297 byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
298 byte_count += total_in_buf2;
299
300 /* BB also add check that we are not beyond maximum buffer size */
301
302 pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
303
304 if(remaining == total_in_buf2) {
305 cFYI(1,("found the last secondary response"));
306 return 0; /* we are done */
307 } else /* more responses to go */
308 return 1;
309
310}
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312static int
313cifs_demultiplex_thread(struct TCP_Server_Info *server)
314{
315 int length;
316 unsigned int pdu_length, total_read;
317 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700318 struct smb_hdr *bigbuf = NULL;
319 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 struct msghdr smb_msg;
321 struct kvec iov;
322 struct socket *csocket = server->ssocket;
323 struct list_head *tmp;
324 struct cifsSesInfo *ses;
325 struct task_struct *task_to_wake = NULL;
326 struct mid_q_entry *mid_entry;
327 char *temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700328 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700329 int isMultiRsp;
330 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 daemonize("cifsd");
333 allow_signal(SIGKILL);
334 current->flags |= PF_MEMALLOC;
335 server->tsk = current; /* save process info to wake at shutdown */
336 cFYI(1, ("Demultiplex PID: %d", current->pid));
337 write_lock(&GlobalSMBSeslock);
338 atomic_inc(&tcpSesAllocCount);
339 length = tcpSesAllocCount.counter;
340 write_unlock(&GlobalSMBSeslock);
341 if(length > 1) {
342 mempool_resize(cifs_req_poolp,
343 length + cifs_min_rcv,
344 GFP_KERNEL);
345 }
346
347 while (server->tcpStatus != CifsExiting) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700348 if (bigbuf == NULL) {
349 bigbuf = cifs_buf_get();
350 if(bigbuf == NULL) {
351 cERROR(1,("No memory for large SMB response"));
352 msleep(3000);
353 /* retry will check if exiting */
354 continue;
355 }
356 } else if(isLargeBuf) {
357 /* we are reusing a dirtry large buf, clear its start */
358 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700360
361 if (smallbuf == NULL) {
362 smallbuf = cifs_small_buf_get();
363 if(smallbuf == NULL) {
364 cERROR(1,("No memory for SMB response"));
365 msleep(1000);
366 /* retry will check if exiting */
367 continue;
368 }
369 /* beginning of smb buffer is cleared in our buf_get */
370 } else /* if existing small buf clear beginning */
371 memset(smallbuf, 0, sizeof (struct smb_hdr));
372
373 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700374 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700375 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 iov.iov_base = smb_buffer;
377 iov.iov_len = 4;
378 smb_msg.msg_control = NULL;
379 smb_msg.msg_controllen = 0;
380 length =
381 kernel_recvmsg(csocket, &smb_msg,
382 &iov, 1, 4, 0 /* BB see socket.h flags */);
383
384 if(server->tcpStatus == CifsExiting) {
385 break;
386 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French57337e42005-04-28 22:41:10 -0700387 cFYI(1,("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 cifs_reconnect(server);
389 cFYI(1,("call to reconnect done"));
390 csocket = server->ssocket;
391 continue;
392 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700393 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 allowing socket to clear and app threads to set
395 tcpStatus CifsNeedReconnect if server hung */
396 continue;
397 } else if (length <= 0) {
398 if(server->tcpStatus == CifsNew) {
Steve French57337e42005-04-28 22:41:10 -0700399 cFYI(1,("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700400 /* some servers kill the TCP session rather than
401 returning an SMB negprot error, in which
402 case reconnecting here is not going to help,
403 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 break;
405 }
406 if(length == -EINTR) {
407 cFYI(1,("cifsd thread killed"));
408 break;
409 }
Steve French57337e42005-04-28 22:41:10 -0700410 cFYI(1,("Reconnect after unexpected peek error %d",
411 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 cifs_reconnect(server);
413 csocket = server->ssocket;
414 wake_up(&server->response_q);
415 continue;
Steve French46810cb2005-04-28 22:41:09 -0700416 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700418 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 length));
420 cifs_reconnect(server);
421 csocket = server->ssocket;
422 wake_up(&server->response_q);
423 continue;
424 }
Steve French67010fb2005-04-28 22:41:09 -0700425
Steve French46810cb2005-04-28 22:41:09 -0700426 /* the right amount was read from socket - 4 bytes */
427
428 pdu_length = ntohl(smb_buffer->smb_buf_length);
429 cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
430
431 temp = (char *) smb_buffer;
432 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700433 continue;
Steve French46810cb2005-04-28 22:41:09 -0700434 } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700435 cFYI(1,("Good RFC 1002 session rsp"));
436 continue;
Steve French46810cb2005-04-28 22:41:09 -0700437 } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
438 /* we get this from Windows 98 instead of
439 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700440 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
441 temp[4]));
Steve French46810cb2005-04-28 22:41:09 -0700442 if(server->tcpStatus == CifsNew) {
443 /* if nack on negprot (rather than
444 ret of smb negprot error) reconnecting
445 not going to help, ret error to mount */
446 break;
447 } else {
448 /* give server a second to
449 clean up before reconnect attempt */
450 msleep(1000);
451 /* always try 445 first on reconnect
452 since we get NACK on some if we ever
453 connected to port 139 (the NACK is
454 since we do not begin with RFC1001
455 session initialize frame) */
456 server->addr.sockAddr.sin_port =
457 htons(CIFS_PORT);
458 cifs_reconnect(server);
459 csocket = server->ssocket;
460 wake_up(&server->response_q);
461 continue;
462 }
463 } else if (temp[0] != (char) 0) {
464 cERROR(1,("Unknown RFC 1002 frame"));
465 cifs_dump_mem(" Received Data: ", temp, length);
466 cifs_reconnect(server);
467 csocket = server->ssocket;
468 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700469 }
470
471 /* else we have an SMB response */
472 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700473 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700474 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700475 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700476 cifs_reconnect(server);
477 csocket = server->ssocket;
478 wake_up(&server->response_q);
479 continue;
480 }
481
482 /* else length ok */
483 reconnect = 0;
484
485 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
486 isLargeBuf = TRUE;
487 memcpy(bigbuf, smallbuf, 4);
488 smb_buffer = bigbuf;
489 }
490 length = 0;
491 iov.iov_base = 4 + (char *)smb_buffer;
492 iov.iov_len = pdu_length;
493 for (total_read = 0; total_read < pdu_length;
494 total_read += length) {
495 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
496 pdu_length - total_read, 0);
497 if((server->tcpStatus == CifsExiting) ||
498 (length == -EINTR)) {
499 /* then will exit */
500 reconnect = 2;
501 break;
502 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700503 cifs_reconnect(server);
504 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 /* Reconnect wakes up rspns q */
506 /* Now we will reread sock */
507 reconnect = 1;
508 break;
509 } else if ((length == -ERESTARTSYS) ||
510 (length == -EAGAIN)) {
511 msleep(1); /* minimum sleep to prevent looping,
512 allowing socket to clear and app
513 threads to set tcpStatus
514 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700515 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700516 } else if (length <= 0) {
517 cERROR(1,("Received no data, expecting %d",
518 pdu_length - total_read));
519 cifs_reconnect(server);
520 csocket = server->ssocket;
521 reconnect = 1;
522 break;
Steve French46810cb2005-04-28 22:41:09 -0700523 }
524 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700525 if(reconnect == 2)
526 break;
527 else if(reconnect == 1)
528 continue;
529
530 length += 4; /* account for rfc1002 hdr */
531
532
533 dump_smb(smb_buffer, length);
534 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
535 cERROR(1, ("Bad SMB Received "));
536 continue;
537 }
538
539
540 task_to_wake = NULL;
541 spin_lock(&GlobalMid_Lock);
542 list_for_each(tmp, &server->pending_mid_q) {
543 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
544
545 if ((mid_entry->mid == smb_buffer->Mid) &&
546 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
547 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
549 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700550 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 if(mid_entry->resp_buf) {
552 /* merge response - fix up 1st*/
553 if(coalesce_t2(smb_buffer,
554 mid_entry->resp_buf)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700555 break;
556 } else {
557 /* all parts received */
558 goto multi_t2_fnd;
559 }
560 } else {
561 if(!isLargeBuf) {
562 cERROR(1,("1st trans2 resp needs bigbuf"));
563 /* BB maybe we can fix this up, switch
564 to already allocated large buffer? */
565 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700566 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700567 mid_entry->resp_buf =
568 smb_buffer;
569 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700570 bigbuf = NULL;
571 }
572 }
573 break;
574 }
575 mid_entry->resp_buf = smb_buffer;
576 if(isLargeBuf)
577 mid_entry->largeBuf = 1;
578 else
579 mid_entry->largeBuf = 0;
580multi_t2_fnd:
581 task_to_wake = mid_entry->tsk;
582 mid_entry->midState = MID_RESPONSE_RECEIVED;
583 break;
584 }
585 }
586 spin_unlock(&GlobalMid_Lock);
587 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700588 /* Was previous buf put in mpx struct for multi-rsp? */
589 if(!isMultiRsp) {
590 /* smb buffer will be freed by user thread */
591 if(isLargeBuf) {
592 bigbuf = NULL;
593 } else
594 smallbuf = NULL;
595 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 wake_up_process(task_to_wake);
Steve French57337e42005-04-28 22:41:10 -0700597 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 && (isMultiRsp == FALSE)) {
599 cERROR(1, ("No task to wake, unknown frame rcvd!"));
600 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
601 }
602 } /* end while !EXITING */
603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 spin_lock(&GlobalMid_Lock);
605 server->tcpStatus = CifsExiting;
606 server->tsk = NULL;
607 atomic_set(&server->inFlight, 0);
608 spin_unlock(&GlobalMid_Lock);
609 /* Although there should not be any requests blocked on
610 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700611 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 to the same server - they now will see the session is in exit state
613 and get out of SendReceive. */
614 wake_up_all(&server->request_q);
615 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700616 msleep(125);
617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if(server->ssocket) {
619 sock_release(csocket);
620 server->ssocket = NULL;
621 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700622 /* buffer usuallly freed in free_mid - need to free it here on exit */
623 if (bigbuf != NULL)
624 cifs_buf_release(bigbuf);
625 if (smallbuf != NULL)
626 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 read_lock(&GlobalSMBSeslock);
629 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700630 /* loop through server session structures attached to this and
631 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 list_for_each(tmp, &GlobalSMBSessionList) {
633 ses =
634 list_entry(tmp, struct cifsSesInfo,
635 cifsSessionList);
636 if (ses->server == server) {
637 ses->status = CifsExiting;
638 ses->server = NULL;
639 }
640 }
641 read_unlock(&GlobalSMBSeslock);
642 } else {
643 spin_lock(&GlobalMid_Lock);
644 list_for_each(tmp, &server->pending_mid_q) {
645 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
646 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
647 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700648 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 task_to_wake = mid_entry->tsk;
650 if(task_to_wake) {
651 wake_up_process(task_to_wake);
652 }
653 }
654 }
655 spin_unlock(&GlobalMid_Lock);
656 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700658 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
660
661 if (list_empty(&server->pending_mid_q)) {
662 /* mpx threads have not exited yet give them
663 at least the smb send timeout time for long ops */
664 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700665 msleep(46);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 /* if threads still have not exited they are probably never
667 coming home not much else we can do but free the memory */
668 }
669 kfree(server);
670
671 write_lock(&GlobalSMBSeslock);
672 atomic_dec(&tcpSesAllocCount);
673 length = tcpSesAllocCount.counter;
674 write_unlock(&GlobalSMBSeslock);
675 if(length > 0) {
676 mempool_resize(cifs_req_poolp,
677 length + cifs_min_rcv,
678 GFP_KERNEL);
679 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700680
681 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 return 0;
683}
684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685static int
686cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
687{
688 char *value;
689 char *data;
690 unsigned int temp_len, i, j;
691 char separator[2];
692
693 separator[0] = ',';
694 separator[1] = 0;
695
696 memset(vol->source_rfc1001_name,0x20,15);
697 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
698 /* does not have to be a perfect mapping since the field is
699 informational, only used for servers that do not support
700 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700701 vol->source_rfc1001_name[i] =
702 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 }
704 vol->source_rfc1001_name[15] = 0;
705
706 vol->linux_uid = current->uid; /* current->euid instead? */
707 vol->linux_gid = current->gid;
708 vol->dir_mode = S_IRWXUGO;
709 /* 2767 perms indicate mandatory locking support */
710 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
711
712 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
713 vol->rw = TRUE;
714
715 if (!options)
716 return 1;
717
718 if(strncmp(options,"sep=",4) == 0) {
719 if(options[4] != 0) {
720 separator[0] = options[4];
721 options += 5;
722 } else {
723 cFYI(1,("Null separator not allowed"));
724 }
725 }
726
727 while ((data = strsep(&options, separator)) != NULL) {
728 if (!*data)
729 continue;
730 if ((value = strchr(data, '=')) != NULL)
731 *value++ = '\0';
732
733 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
734 vol->no_xattr = 0;
735 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
736 vol->no_xattr = 1;
737 } else if (strnicmp(data, "user", 4) == 0) {
738 if (!value || !*value) {
739 printk(KERN_WARNING
740 "CIFS: invalid or missing username\n");
741 return 1; /* needs_arg; */
742 }
743 if (strnlen(value, 200) < 200) {
744 vol->username = value;
745 } else {
746 printk(KERN_WARNING "CIFS: username too long\n");
747 return 1;
748 }
749 } else if (strnicmp(data, "pass", 4) == 0) {
750 if (!value) {
751 vol->password = NULL;
752 continue;
753 } else if(value[0] == 0) {
754 /* check if string begins with double comma
755 since that would mean the password really
756 does start with a comma, and would not
757 indicate an empty string */
758 if(value[1] != separator[0]) {
759 vol->password = NULL;
760 continue;
761 }
762 }
763 temp_len = strlen(value);
764 /* removed password length check, NTLM passwords
765 can be arbitrarily long */
766
767 /* if comma in password, the string will be
768 prematurely null terminated. Commas in password are
769 specified across the cifs mount interface by a double
770 comma ie ,, and a comma used as in other cases ie ','
771 as a parameter delimiter/separator is single and due
772 to the strsep above is temporarily zeroed. */
773
774 /* NB: password legally can have multiple commas and
775 the only illegal character in a password is null */
776
Steve French09d1db52005-04-28 22:41:08 -0700777 if ((value[temp_len] == 0) &&
778 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 /* reinsert comma */
780 value[temp_len] = separator[0];
781 temp_len+=2; /* move after the second comma */
782 while(value[temp_len] != 0) {
783 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700784 if (value[temp_len+1] ==
785 separator[0]) {
786 /* skip second comma */
787 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 } else {
789 /* single comma indicating start
790 of next parm */
791 break;
792 }
793 }
794 temp_len++;
795 }
796 if(value[temp_len] == 0) {
797 options = NULL;
798 } else {
799 value[temp_len] = 0;
800 /* point option to start of next parm */
801 options = value + temp_len + 1;
802 }
803 /* go from value to value + temp_len condensing
804 double commas to singles. Note that this ends up
805 allocating a few bytes too many, which is ok */
Steve French433dc242005-04-28 22:41:08 -0700806 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
807 if(vol->password == NULL) {
808 printk("CIFS: no memory for pass\n");
809 return 1;
810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 for(i=0,j=0;i<temp_len;i++,j++) {
812 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700813 if(value[i] == separator[0]
814 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 /* skip second comma */
816 i++;
817 }
818 }
819 vol->password[j] = 0;
820 } else {
Steve French09d1db52005-04-28 22:41:08 -0700821 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700822 if(vol->password == NULL) {
823 printk("CIFS: no memory for pass\n");
824 return 1;
825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 strcpy(vol->password, value);
827 }
828 } else if (strnicmp(data, "ip", 2) == 0) {
829 if (!value || !*value) {
830 vol->UNCip = NULL;
831 } else if (strnlen(value, 35) < 35) {
832 vol->UNCip = value;
833 } else {
834 printk(KERN_WARNING "CIFS: ip address too long\n");
835 return 1;
836 }
837 } else if ((strnicmp(data, "unc", 3) == 0)
838 || (strnicmp(data, "target", 6) == 0)
839 || (strnicmp(data, "path", 4) == 0)) {
840 if (!value || !*value) {
841 printk(KERN_WARNING
842 "CIFS: invalid path to network resource\n");
843 return 1; /* needs_arg; */
844 }
845 if ((temp_len = strnlen(value, 300)) < 300) {
846 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
847 if(vol->UNC == NULL)
848 return 1;
849 strcpy(vol->UNC,value);
850 if (strncmp(vol->UNC, "//", 2) == 0) {
851 vol->UNC[0] = '\\';
852 vol->UNC[1] = '\\';
853 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
854 printk(KERN_WARNING
855 "CIFS: UNC Path does not begin with // or \\\\ \n");
856 return 1;
857 }
858 } else {
859 printk(KERN_WARNING "CIFS: UNC name too long\n");
860 return 1;
861 }
862 } else if ((strnicmp(data, "domain", 3) == 0)
863 || (strnicmp(data, "workgroup", 5) == 0)) {
864 if (!value || !*value) {
865 printk(KERN_WARNING "CIFS: invalid domain name\n");
866 return 1; /* needs_arg; */
867 }
868 /* BB are there cases in which a comma can be valid in
869 a domain name and need special handling? */
870 if (strnlen(value, 65) < 65) {
871 vol->domainname = value;
872 cFYI(1, ("Domain name set"));
873 } else {
874 printk(KERN_WARNING "CIFS: domain name too long\n");
875 return 1;
876 }
877 } else if (strnicmp(data, "iocharset", 9) == 0) {
878 if (!value || !*value) {
879 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
880 return 1; /* needs_arg; */
881 }
882 if (strnlen(value, 65) < 65) {
883 if(strnicmp(value,"default",7))
884 vol->iocharset = value;
885 /* if iocharset not set load_nls_default used by caller */
886 cFYI(1, ("iocharset set to %s",value));
887 } else {
888 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
889 return 1;
890 }
891 } else if (strnicmp(data, "uid", 3) == 0) {
892 if (value && *value) {
893 vol->linux_uid =
894 simple_strtoul(value, &value, 0);
895 }
896 } else if (strnicmp(data, "gid", 3) == 0) {
897 if (value && *value) {
898 vol->linux_gid =
899 simple_strtoul(value, &value, 0);
900 }
901 } else if (strnicmp(data, "file_mode", 4) == 0) {
902 if (value && *value) {
903 vol->file_mode =
904 simple_strtoul(value, &value, 0);
905 }
906 } else if (strnicmp(data, "dir_mode", 4) == 0) {
907 if (value && *value) {
908 vol->dir_mode =
909 simple_strtoul(value, &value, 0);
910 }
911 } else if (strnicmp(data, "dirmode", 4) == 0) {
912 if (value && *value) {
913 vol->dir_mode =
914 simple_strtoul(value, &value, 0);
915 }
916 } else if (strnicmp(data, "port", 4) == 0) {
917 if (value && *value) {
918 vol->port =
919 simple_strtoul(value, &value, 0);
920 }
921 } else if (strnicmp(data, "rsize", 5) == 0) {
922 if (value && *value) {
923 vol->rsize =
924 simple_strtoul(value, &value, 0);
925 }
926 } else if (strnicmp(data, "wsize", 5) == 0) {
927 if (value && *value) {
928 vol->wsize =
929 simple_strtoul(value, &value, 0);
930 }
931 } else if (strnicmp(data, "sockopt", 5) == 0) {
932 if (value && *value) {
933 vol->sockopt =
934 simple_strtoul(value, &value, 0);
935 }
936 } else if (strnicmp(data, "netbiosname", 4) == 0) {
937 if (!value || !*value || (*value == ' ')) {
938 cFYI(1,("invalid (empty) netbiosname specified"));
939 } else {
940 memset(vol->source_rfc1001_name,0x20,15);
941 for(i=0;i<15;i++) {
942 /* BB are there cases in which a comma can be
943 valid in this workstation netbios name (and need
944 special handling)? */
945
946 /* We do not uppercase netbiosname for user */
947 if (value[i]==0)
948 break;
949 else
950 vol->source_rfc1001_name[i] = value[i];
951 }
952 /* The string has 16th byte zero still from
953 set at top of the function */
954 if((i==15) && (value[i] != 0))
955 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
956 }
957 } else if (strnicmp(data, "credentials", 4) == 0) {
958 /* ignore */
959 } else if (strnicmp(data, "version", 3) == 0) {
960 /* ignore */
961 } else if (strnicmp(data, "guest",5) == 0) {
962 /* ignore */
963 } else if (strnicmp(data, "rw", 2) == 0) {
964 vol->rw = TRUE;
965 } else if ((strnicmp(data, "suid", 4) == 0) ||
966 (strnicmp(data, "nosuid", 6) == 0) ||
967 (strnicmp(data, "exec", 4) == 0) ||
968 (strnicmp(data, "noexec", 6) == 0) ||
969 (strnicmp(data, "nodev", 5) == 0) ||
970 (strnicmp(data, "noauto", 6) == 0) ||
971 (strnicmp(data, "dev", 3) == 0)) {
972 /* The mount tool or mount.cifs helper (if present)
973 uses these opts to set flags, and the flags are read
974 by the kernel vfs layer before we get here (ie
975 before read super) so there is no point trying to
976 parse these options again and set anything and it
977 is ok to just ignore them */
978 continue;
979 } else if (strnicmp(data, "ro", 2) == 0) {
980 vol->rw = FALSE;
981 } else if (strnicmp(data, "hard", 4) == 0) {
982 vol->retry = 1;
983 } else if (strnicmp(data, "soft", 4) == 0) {
984 vol->retry = 0;
985 } else if (strnicmp(data, "perm", 4) == 0) {
986 vol->noperm = 0;
987 } else if (strnicmp(data, "noperm", 6) == 0) {
988 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -0700989 } else if (strnicmp(data, "mapchars", 8) == 0) {
990 vol->remap = 1;
991 } else if (strnicmp(data, "nomapchars", 10) == 0) {
992 vol->remap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 } else if (strnicmp(data, "setuids", 7) == 0) {
994 vol->setuids = 1;
995 } else if (strnicmp(data, "nosetuids", 9) == 0) {
996 vol->setuids = 0;
997 } else if (strnicmp(data, "nohard", 6) == 0) {
998 vol->retry = 0;
999 } else if (strnicmp(data, "nosoft", 6) == 0) {
1000 vol->retry = 1;
1001 } else if (strnicmp(data, "nointr", 6) == 0) {
1002 vol->intr = 0;
1003 } else if (strnicmp(data, "intr", 4) == 0) {
1004 vol->intr = 1;
1005 } else if (strnicmp(data, "serverino",7) == 0) {
1006 vol->server_ino = 1;
1007 } else if (strnicmp(data, "noserverino",9) == 0) {
1008 vol->server_ino = 0;
1009 } else if (strnicmp(data, "acl",3) == 0) {
1010 vol->no_psx_acl = 0;
1011 } else if (strnicmp(data, "noacl",5) == 0) {
1012 vol->no_psx_acl = 1;
1013 } else if (strnicmp(data, "direct",6) == 0) {
1014 vol->direct_io = 1;
1015 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1016 vol->direct_io = 1;
1017 } else if (strnicmp(data, "in6_addr",8) == 0) {
1018 if (!value || !*value) {
1019 vol->in6_addr = NULL;
1020 } else if (strnlen(value, 49) == 48) {
1021 vol->in6_addr = value;
1022 } else {
1023 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1024 return 1;
1025 }
1026 } else if (strnicmp(data, "noac", 4) == 0) {
1027 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1028 } else
1029 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1030 }
1031 if (vol->UNC == NULL) {
1032 if(devname == NULL) {
1033 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1034 return 1;
1035 }
1036 if ((temp_len = strnlen(devname, 300)) < 300) {
1037 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1038 if(vol->UNC == NULL)
1039 return 1;
1040 strcpy(vol->UNC,devname);
1041 if (strncmp(vol->UNC, "//", 2) == 0) {
1042 vol->UNC[0] = '\\';
1043 vol->UNC[1] = '\\';
1044 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1045 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1046 return 1;
1047 }
1048 } else {
1049 printk(KERN_WARNING "CIFS: UNC name too long\n");
1050 return 1;
1051 }
1052 }
1053 if(vol->UNCip == NULL)
1054 vol->UNCip = &vol->UNC[2];
1055
1056 return 0;
1057}
1058
1059static struct cifsSesInfo *
1060cifs_find_tcp_session(struct in_addr * target_ip_addr,
1061 struct in6_addr *target_ip6_addr,
1062 char *userName, struct TCP_Server_Info **psrvTcp)
1063{
1064 struct list_head *tmp;
1065 struct cifsSesInfo *ses;
1066 *psrvTcp = NULL;
1067 read_lock(&GlobalSMBSeslock);
1068
1069 list_for_each(tmp, &GlobalSMBSessionList) {
1070 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1071 if (ses->server) {
1072 if((target_ip_addr &&
1073 (ses->server->addr.sockAddr.sin_addr.s_addr
1074 == target_ip_addr->s_addr)) || (target_ip6_addr
1075 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1076 target_ip6_addr,sizeof(*target_ip6_addr)))){
1077 /* BB lock server and tcp session and increment use count here?? */
1078 *psrvTcp = ses->server; /* found a match on the TCP session */
1079 /* BB check if reconnection needed */
1080 if (strncmp
1081 (ses->userName, userName,
1082 MAX_USERNAME_SIZE) == 0){
1083 read_unlock(&GlobalSMBSeslock);
1084 return ses; /* found exact match on both tcp and SMB sessions */
1085 }
1086 }
1087 }
1088 /* else tcp and smb sessions need reconnection */
1089 }
1090 read_unlock(&GlobalSMBSeslock);
1091 return NULL;
1092}
1093
1094static struct cifsTconInfo *
1095find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1096{
1097 struct list_head *tmp;
1098 struct cifsTconInfo *tcon;
1099
1100 read_lock(&GlobalSMBSeslock);
1101 list_for_each(tmp, &GlobalTreeConnectionList) {
1102 cFYI(1, ("Next tcon - "));
1103 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1104 if (tcon->ses) {
1105 if (tcon->ses->server) {
1106 cFYI(1,
1107 (" old ip addr: %x == new ip %x ?",
1108 tcon->ses->server->addr.sockAddr.sin_addr.
1109 s_addr, new_target_ip_addr));
1110 if (tcon->ses->server->addr.sockAddr.sin_addr.
1111 s_addr == new_target_ip_addr) {
1112 /* BB lock tcon and server and tcp session and increment use count here? */
1113 /* found a match on the TCP session */
1114 /* BB check if reconnection needed */
1115 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1116 tcon->treeName, uncName));
1117 if (strncmp
1118 (tcon->treeName, uncName,
1119 MAX_TREE_SIZE) == 0) {
1120 cFYI(1,
1121 ("Matched UNC, old user: %s == new: %s ?",
1122 tcon->treeName, uncName));
1123 if (strncmp
1124 (tcon->ses->userName,
1125 userName,
1126 MAX_USERNAME_SIZE) == 0) {
1127 read_unlock(&GlobalSMBSeslock);
1128 return tcon;/* also matched user (smb session)*/
1129 }
1130 }
1131 }
1132 }
1133 }
1134 }
1135 read_unlock(&GlobalSMBSeslock);
1136 return NULL;
1137}
1138
1139int
1140connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001141 const char *old_path, const struct nls_table *nls_codepage,
1142 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 unsigned char *referrals = NULL;
1145 unsigned int num_referrals;
1146 int rc = 0;
1147
1148 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001149 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 /* BB Add in code to: if valid refrl, if not ip address contact
1152 the helper that resolves tcp names, mount to it, try to
1153 tcon to it unmount it if fail */
1154
1155 if(referrals)
1156 kfree(referrals);
1157
1158 return rc;
1159}
1160
1161int
1162get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1163 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001164 unsigned int *pnum_referrals,
1165 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166{
1167 char *temp_unc;
1168 int rc = 0;
1169
1170 *pnum_referrals = 0;
1171
1172 if (pSesInfo->ipc_tid == 0) {
1173 temp_unc = kmalloc(2 /* for slashes */ +
1174 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1175 + 1 + 4 /* slash IPC$ */ + 2,
1176 GFP_KERNEL);
1177 if (temp_unc == NULL)
1178 return -ENOMEM;
1179 temp_unc[0] = '\\';
1180 temp_unc[1] = '\\';
1181 strcpy(temp_unc + 2, pSesInfo->serverName);
1182 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1183 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1184 cFYI(1,
1185 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1186 kfree(temp_unc);
1187 }
1188 if (rc == 0)
1189 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001190 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 return rc;
1193}
1194
1195/* See RFC1001 section 14 on representation of Netbios names */
1196static void rfc1002mangle(char * target,char * source, unsigned int length)
1197{
1198 unsigned int i,j;
1199
1200 for(i=0,j=0;i<(length);i++) {
1201 /* mask a nibble at a time and encode */
1202 target[j] = 'A' + (0x0F & (source[i] >> 4));
1203 target[j+1] = 'A' + (0x0F & source[i]);
1204 j+=2;
1205 }
1206
1207}
1208
1209
1210static int
1211ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1212 char * netbios_name)
1213{
1214 int rc = 0;
1215 int connected = 0;
1216 __be16 orig_port = 0;
1217
1218 if(*csocket == NULL) {
1219 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1220 if (rc < 0) {
1221 cERROR(1, ("Error %d creating socket",rc));
1222 *csocket = NULL;
1223 return rc;
1224 } else {
1225 /* BB other socket options to set KEEPALIVE, NODELAY? */
1226 cFYI(1,("Socket created"));
1227 (*csocket)->sk->sk_allocation = GFP_NOFS;
1228 }
1229 }
1230
1231 psin_server->sin_family = AF_INET;
1232 if(psin_server->sin_port) { /* user overrode default port */
1233 rc = (*csocket)->ops->connect(*csocket,
1234 (struct sockaddr *) psin_server,
1235 sizeof (struct sockaddr_in),0);
1236 if (rc >= 0)
1237 connected = 1;
1238 }
1239
1240 if(!connected) {
1241 /* save original port so we can retry user specified port
1242 later if fall back ports fail this time */
1243 orig_port = psin_server->sin_port;
1244
1245 /* do not retry on the same port we just failed on */
1246 if(psin_server->sin_port != htons(CIFS_PORT)) {
1247 psin_server->sin_port = htons(CIFS_PORT);
1248
1249 rc = (*csocket)->ops->connect(*csocket,
1250 (struct sockaddr *) psin_server,
1251 sizeof (struct sockaddr_in),0);
1252 if (rc >= 0)
1253 connected = 1;
1254 }
1255 }
1256 if (!connected) {
1257 psin_server->sin_port = htons(RFC1001_PORT);
1258 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1259 psin_server, sizeof (struct sockaddr_in),0);
1260 if (rc >= 0)
1261 connected = 1;
1262 }
1263
1264 /* give up here - unless we want to retry on different
1265 protocol families some day */
1266 if (!connected) {
1267 if(orig_port)
1268 psin_server->sin_port = orig_port;
1269 cFYI(1,("Error %d connecting to server via ipv4",rc));
1270 sock_release(*csocket);
1271 *csocket = NULL;
1272 return rc;
1273 }
1274 /* Eventually check for other socket options to change from
1275 the default. sock_setsockopt not used because it expects
1276 user space buffer */
1277 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1278
1279 /* send RFC1001 sessinit */
1280
1281 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1282 /* some servers require RFC1001 sessinit before sending
1283 negprot - BB check reconnection in case where second
1284 sessinit is sent but no second negprot */
1285 struct rfc1002_session_packet * ses_init_buf;
1286 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001287 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 if(ses_init_buf) {
1289 ses_init_buf->trailer.session_req.called_len = 32;
1290 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1291 DEFAULT_CIFS_CALLED_NAME,16);
1292 ses_init_buf->trailer.session_req.calling_len = 32;
1293 /* calling name ends in null (byte 16) from old smb
1294 convention. */
1295 if(netbios_name && (netbios_name[0] !=0)) {
1296 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1297 netbios_name,16);
1298 } else {
1299 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1300 "LINUX_CIFS_CLNT",16);
1301 }
1302 ses_init_buf->trailer.session_req.scope1 = 0;
1303 ses_init_buf->trailer.session_req.scope2 = 0;
1304 smb_buf = (struct smb_hdr *)ses_init_buf;
1305 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1306 smb_buf->smb_buf_length = 0x81000044;
1307 rc = smb_send(*csocket, smb_buf, 0x44,
1308 (struct sockaddr *)psin_server);
1309 kfree(ses_init_buf);
1310 }
1311 /* else the negprot may still work without this
1312 even though malloc failed */
1313
1314 }
1315
1316 return rc;
1317}
1318
1319static int
1320ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1321{
1322 int rc = 0;
1323 int connected = 0;
1324 __be16 orig_port = 0;
1325
1326 if(*csocket == NULL) {
1327 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1328 if (rc < 0) {
1329 cERROR(1, ("Error %d creating ipv6 socket",rc));
1330 *csocket = NULL;
1331 return rc;
1332 } else {
1333 /* BB other socket options to set KEEPALIVE, NODELAY? */
1334 cFYI(1,("ipv6 Socket created"));
1335 (*csocket)->sk->sk_allocation = GFP_NOFS;
1336 }
1337 }
1338
1339 psin_server->sin6_family = AF_INET6;
1340
1341 if(psin_server->sin6_port) { /* user overrode default port */
1342 rc = (*csocket)->ops->connect(*csocket,
1343 (struct sockaddr *) psin_server,
1344 sizeof (struct sockaddr_in6),0);
1345 if (rc >= 0)
1346 connected = 1;
1347 }
1348
1349 if(!connected) {
1350 /* save original port so we can retry user specified port
1351 later if fall back ports fail this time */
1352
1353 orig_port = psin_server->sin6_port;
1354 /* do not retry on the same port we just failed on */
1355 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1356 psin_server->sin6_port = htons(CIFS_PORT);
1357
1358 rc = (*csocket)->ops->connect(*csocket,
1359 (struct sockaddr *) psin_server,
1360 sizeof (struct sockaddr_in6),0);
1361 if (rc >= 0)
1362 connected = 1;
1363 }
1364 }
1365 if (!connected) {
1366 psin_server->sin6_port = htons(RFC1001_PORT);
1367 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1368 psin_server, sizeof (struct sockaddr_in6),0);
1369 if (rc >= 0)
1370 connected = 1;
1371 }
1372
1373 /* give up here - unless we want to retry on different
1374 protocol families some day */
1375 if (!connected) {
1376 if(orig_port)
1377 psin_server->sin6_port = orig_port;
1378 cFYI(1,("Error %d connecting to server via ipv6",rc));
1379 sock_release(*csocket);
1380 *csocket = NULL;
1381 return rc;
1382 }
1383 /* Eventually check for other socket options to change from
1384 the default. sock_setsockopt not used because it expects
1385 user space buffer */
1386 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1387
1388 return rc;
1389}
1390
1391int
1392cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1393 char *mount_data, const char *devname)
1394{
1395 int rc = 0;
1396 int xid;
1397 int address_type = AF_INET;
1398 struct socket *csocket = NULL;
1399 struct sockaddr_in sin_server;
1400 struct sockaddr_in6 sin_server6;
1401 struct smb_vol volume_info;
1402 struct cifsSesInfo *pSesInfo = NULL;
1403 struct cifsSesInfo *existingCifsSes = NULL;
1404 struct cifsTconInfo *tcon = NULL;
1405 struct TCP_Server_Info *srvTcp = NULL;
1406
1407 xid = GetXid();
1408
1409/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1410
1411 memset(&volume_info,0,sizeof(struct smb_vol));
1412 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1413 if(volume_info.UNC)
1414 kfree(volume_info.UNC);
1415 if(volume_info.password)
1416 kfree(volume_info.password);
1417 FreeXid(xid);
1418 return -EINVAL;
1419 }
1420
1421 if (volume_info.username) {
1422 /* BB fixme parse for domain name here */
1423 cFYI(1, ("Username: %s ", volume_info.username));
1424
1425 } else {
1426 cifserror("No username specified ");
1427 /* In userspace mount helper we can get user name from alternate
1428 locations such as env variables and files on disk */
1429 if(volume_info.UNC)
1430 kfree(volume_info.UNC);
1431 if(volume_info.password)
1432 kfree(volume_info.password);
1433 FreeXid(xid);
1434 return -EINVAL;
1435 }
1436
1437 if (volume_info.UNCip && volume_info.UNC) {
1438 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1439
1440 if(rc <= 0) {
1441 /* not ipv4 address, try ipv6 */
1442 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1443 if(rc > 0)
1444 address_type = AF_INET6;
1445 } else {
1446 address_type = AF_INET;
1447 }
1448
1449 if(rc <= 0) {
1450 /* we failed translating address */
1451 if(volume_info.UNC)
1452 kfree(volume_info.UNC);
1453 if(volume_info.password)
1454 kfree(volume_info.password);
1455 FreeXid(xid);
1456 return -EINVAL;
1457 }
1458
1459 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1460 /* success */
1461 rc = 0;
1462 } else if (volume_info.UNCip){
1463 /* BB using ip addr as server name connect to the DFS root below */
1464 cERROR(1,("Connecting to DFS root not implemented yet"));
1465 if(volume_info.UNC)
1466 kfree(volume_info.UNC);
1467 if(volume_info.password)
1468 kfree(volume_info.password);
1469 FreeXid(xid);
1470 return -EINVAL;
1471 } else /* which servers DFS root would we conect to */ {
1472 cERROR(1,
1473 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1474 if(volume_info.UNC)
1475 kfree(volume_info.UNC);
1476 if(volume_info.password)
1477 kfree(volume_info.password);
1478 FreeXid(xid);
1479 return -EINVAL;
1480 }
1481
1482 /* this is needed for ASCII cp to Unicode converts */
1483 if(volume_info.iocharset == NULL) {
1484 cifs_sb->local_nls = load_nls_default();
1485 /* load_nls_default can not return null */
1486 } else {
1487 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1488 if(cifs_sb->local_nls == NULL) {
1489 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1490 if(volume_info.UNC)
1491 kfree(volume_info.UNC);
1492 if(volume_info.password)
1493 kfree(volume_info.password);
1494 FreeXid(xid);
1495 return -ELIBACC;
1496 }
1497 }
1498
1499 if(address_type == AF_INET)
1500 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1501 NULL /* no ipv6 addr */,
1502 volume_info.username, &srvTcp);
1503 else if(address_type == AF_INET6)
1504 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1505 &sin_server6.sin6_addr,
1506 volume_info.username, &srvTcp);
1507 else {
1508 if(volume_info.UNC)
1509 kfree(volume_info.UNC);
1510 if(volume_info.password)
1511 kfree(volume_info.password);
1512 FreeXid(xid);
1513 return -EINVAL;
1514 }
1515
1516
1517 if (srvTcp) {
1518 cFYI(1, ("Existing tcp session with server found "));
1519 } else { /* create socket */
1520 if(volume_info.port)
1521 sin_server.sin_port = htons(volume_info.port);
1522 else
1523 sin_server.sin_port = 0;
1524 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1525 if (rc < 0) {
1526 cERROR(1,
1527 ("Error connecting to IPv4 socket. Aborting operation"));
1528 if(csocket != NULL)
1529 sock_release(csocket);
1530 if(volume_info.UNC)
1531 kfree(volume_info.UNC);
1532 if(volume_info.password)
1533 kfree(volume_info.password);
1534 FreeXid(xid);
1535 return rc;
1536 }
1537
1538 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1539 if (srvTcp == NULL) {
1540 rc = -ENOMEM;
1541 sock_release(csocket);
1542 if(volume_info.UNC)
1543 kfree(volume_info.UNC);
1544 if(volume_info.password)
1545 kfree(volume_info.password);
1546 FreeXid(xid);
1547 return rc;
1548 } else {
1549 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1550 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1551 atomic_set(&srvTcp->inFlight,0);
1552 /* BB Add code for ipv6 case too */
1553 srvTcp->ssocket = csocket;
1554 srvTcp->protocolType = IPV4;
1555 init_waitqueue_head(&srvTcp->response_q);
1556 init_waitqueue_head(&srvTcp->request_q);
1557 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1558 /* at this point we are the only ones with the pointer
1559 to the struct since the kernel thread not created yet
1560 so no need to spinlock this init of tcpStatus */
1561 srvTcp->tcpStatus = CifsNew;
1562 init_MUTEX(&srvTcp->tcpSem);
1563 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1564 CLONE_FS | CLONE_FILES | CLONE_VM);
1565 if(rc < 0) {
1566 rc = -ENOMEM;
1567 sock_release(csocket);
1568 if(volume_info.UNC)
1569 kfree(volume_info.UNC);
1570 if(volume_info.password)
1571 kfree(volume_info.password);
1572 FreeXid(xid);
1573 return rc;
1574 } else
1575 rc = 0;
1576 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001577 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 }
1579 }
1580
1581 if (existingCifsSes) {
1582 pSesInfo = existingCifsSes;
1583 cFYI(1, ("Existing smb sess found "));
1584 if(volume_info.password)
1585 kfree(volume_info.password);
1586 /* volume_info.UNC freed at end of function */
1587 } else if (!rc) {
1588 cFYI(1, ("Existing smb sess not found "));
1589 pSesInfo = sesInfoAlloc();
1590 if (pSesInfo == NULL)
1591 rc = -ENOMEM;
1592 else {
1593 pSesInfo->server = srvTcp;
1594 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1595 NIPQUAD(sin_server.sin_addr.s_addr));
1596 }
1597
1598 if (!rc){
1599 /* volume_info.password freed at unmount */
1600 if (volume_info.password)
1601 pSesInfo->password = volume_info.password;
1602 if (volume_info.username)
1603 strncpy(pSesInfo->userName,
1604 volume_info.username,MAX_USERNAME_SIZE);
1605 if (volume_info.domainname)
1606 strncpy(pSesInfo->domainName,
1607 volume_info.domainname,MAX_USERNAME_SIZE);
1608 pSesInfo->linux_uid = volume_info.linux_uid;
1609 down(&pSesInfo->sesSem);
1610 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1611 up(&pSesInfo->sesSem);
1612 if(!rc)
1613 atomic_inc(&srvTcp->socketUseCount);
1614 } else
1615 if(volume_info.password)
1616 kfree(volume_info.password);
1617 }
1618
1619 /* search for existing tcon to this server share */
1620 if (!rc) {
1621 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1622 cifs_sb->rsize = volume_info.rsize;
1623 else
1624 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1625 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1626 cifs_sb->wsize = volume_info.wsize;
1627 else
1628 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1629 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1630 cifs_sb->rsize = PAGE_CACHE_SIZE;
1631 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1632 }
1633 cifs_sb->mnt_uid = volume_info.linux_uid;
1634 cifs_sb->mnt_gid = volume_info.linux_gid;
1635 cifs_sb->mnt_file_mode = volume_info.file_mode;
1636 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1637 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1638
1639 if(volume_info.noperm)
1640 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1641 if(volume_info.setuids)
1642 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1643 if(volume_info.server_ino)
1644 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001645 if(volume_info.remap)
1646 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 if(volume_info.no_xattr)
1648 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1649 if(volume_info.direct_io) {
1650 cERROR(1,("mounting share using direct i/o"));
1651 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1652 }
1653
1654 tcon =
1655 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1656 volume_info.username);
1657 if (tcon) {
1658 cFYI(1, ("Found match on UNC path "));
1659 /* we can have only one retry value for a connection
1660 to a share so for resources mounted more than once
1661 to the same server share the last value passed in
1662 for the retry flag is used */
1663 tcon->retry = volume_info.retry;
1664 } else {
1665 tcon = tconInfoAlloc();
1666 if (tcon == NULL)
1667 rc = -ENOMEM;
1668 else {
1669 /* check for null share name ie connect to dfs root */
1670
1671 /* BB check if this works for exactly length three strings */
1672 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1673 && (strchr(volume_info.UNC + 3, '/') ==
1674 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001675 rc = connect_to_dfs_path(xid, pSesInfo,
1676 "", cifs_sb->local_nls,
1677 cifs_sb->mnt_cifs_flags &
1678 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 if(volume_info.UNC)
1680 kfree(volume_info.UNC);
1681 FreeXid(xid);
1682 return -ENODEV;
1683 } else {
1684 rc = CIFSTCon(xid, pSesInfo,
1685 volume_info.UNC,
1686 tcon, cifs_sb->local_nls);
1687 cFYI(1, ("CIFS Tcon rc = %d", rc));
1688 }
1689 if (!rc) {
1690 atomic_inc(&pSesInfo->inUse);
1691 tcon->retry = volume_info.retry;
1692 }
1693 }
1694 }
1695 }
1696 if(pSesInfo) {
1697 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1698 sb->s_maxbytes = (u64) 1 << 63;
1699 } else
1700 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1701 }
1702
1703 sb->s_time_gran = 100;
1704
1705/* on error free sesinfo and tcon struct if needed */
1706 if (rc) {
1707 /* if session setup failed, use count is zero but
1708 we still need to free cifsd thread */
1709 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1710 spin_lock(&GlobalMid_Lock);
1711 srvTcp->tcpStatus = CifsExiting;
1712 spin_unlock(&GlobalMid_Lock);
1713 if(srvTcp->tsk)
1714 send_sig(SIGKILL,srvTcp->tsk,1);
1715 }
1716 /* If find_unc succeeded then rc == 0 so we can not end */
1717 if (tcon) /* up accidently freeing someone elses tcon struct */
1718 tconInfoFree(tcon);
1719 if (existingCifsSes == NULL) {
1720 if (pSesInfo) {
1721 if ((pSesInfo->server) &&
1722 (pSesInfo->status == CifsGood)) {
1723 int temp_rc;
1724 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1725 /* if the socketUseCount is now zero */
1726 if((temp_rc == -ESHUTDOWN) &&
1727 (pSesInfo->server->tsk))
1728 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1729 } else
1730 cFYI(1, ("No session or bad tcon"));
1731 sesInfoFree(pSesInfo);
1732 /* pSesInfo = NULL; */
1733 }
1734 }
1735 } else {
1736 atomic_inc(&tcon->useCount);
1737 cifs_sb->tcon = tcon;
1738 tcon->ses = pSesInfo;
1739
1740 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001741 CIFSSMBQFSDeviceInfo(xid, tcon);
1742 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001744 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 if(!volume_info.no_psx_acl) {
1746 if(CIFS_UNIX_POSIX_ACL_CAP &
1747 le64_to_cpu(tcon->fsUnixInfo.Capability))
1748 cFYI(1,("server negotiated posix acl support"));
1749 sb->s_flags |= MS_POSIXACL;
1750 }
1751 }
1752 }
1753 }
1754
1755 /* volume_info.password is freed above when existing session found
1756 (in which case it is not needed anymore) but when new sesion is created
1757 the password ptr is put in the new session structure (in which case the
1758 password will be freed at unmount time) */
1759 if(volume_info.UNC)
1760 kfree(volume_info.UNC);
1761 FreeXid(xid);
1762 return rc;
1763}
1764
1765static int
1766CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1767 char session_key[CIFS_SESSION_KEY_SIZE],
1768 const struct nls_table *nls_codepage)
1769{
1770 struct smb_hdr *smb_buffer;
1771 struct smb_hdr *smb_buffer_response;
1772 SESSION_SETUP_ANDX *pSMB;
1773 SESSION_SETUP_ANDX *pSMBr;
1774 char *bcc_ptr;
1775 char *user;
1776 char *domain;
1777 int rc = 0;
1778 int remaining_words = 0;
1779 int bytes_returned = 0;
1780 int len;
1781 __u32 capabilities;
1782 __u16 count;
1783
1784 cFYI(1, ("In sesssetup "));
1785 if(ses == NULL)
1786 return -EINVAL;
1787 user = ses->userName;
1788 domain = ses->domainName;
1789 smb_buffer = cifs_buf_get();
1790 if (smb_buffer == NULL) {
1791 return -ENOMEM;
1792 }
1793 smb_buffer_response = smb_buffer;
1794 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1795
1796 /* send SMBsessionSetup here */
1797 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1798 NULL /* no tCon exists yet */ , 13 /* wct */ );
1799
1800 pSMB->req_no_secext.AndXCommand = 0xFF;
1801 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1802 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1803
1804 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1805 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1806
1807 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1808 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1809 if (ses->capabilities & CAP_UNICODE) {
1810 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1811 capabilities |= CAP_UNICODE;
1812 }
1813 if (ses->capabilities & CAP_STATUS32) {
1814 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1815 capabilities |= CAP_STATUS32;
1816 }
1817 if (ses->capabilities & CAP_DFS) {
1818 smb_buffer->Flags2 |= SMBFLG2_DFS;
1819 capabilities |= CAP_DFS;
1820 }
1821 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1822
1823 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1824 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1825
1826 pSMB->req_no_secext.CaseSensitivePasswordLength =
1827 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1828 bcc_ptr = pByteArea(smb_buffer);
1829 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1830 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1831 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1832 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1833
1834 if (ses->capabilities & CAP_UNICODE) {
1835 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1836 *bcc_ptr = 0;
1837 bcc_ptr++;
1838 }
1839 if(user == NULL)
1840 bytes_returned = 0; /* skill null user */
1841 else
1842 bytes_returned =
1843 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1844 nls_codepage);
1845 /* convert number of 16 bit words to bytes */
1846 bcc_ptr += 2 * bytes_returned;
1847 bcc_ptr += 2; /* trailing null */
1848 if (domain == NULL)
1849 bytes_returned =
1850 cifs_strtoUCS((wchar_t *) bcc_ptr,
1851 "CIFS_LINUX_DOM", 32, nls_codepage);
1852 else
1853 bytes_returned =
1854 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1855 nls_codepage);
1856 bcc_ptr += 2 * bytes_returned;
1857 bcc_ptr += 2;
1858 bytes_returned =
1859 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1860 32, nls_codepage);
1861 bcc_ptr += 2 * bytes_returned;
1862 bytes_returned =
1863 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1864 32, nls_codepage);
1865 bcc_ptr += 2 * bytes_returned;
1866 bcc_ptr += 2;
1867 bytes_returned =
1868 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1869 64, nls_codepage);
1870 bcc_ptr += 2 * bytes_returned;
1871 bcc_ptr += 2;
1872 } else {
1873 if(user != NULL) {
1874 strncpy(bcc_ptr, user, 200);
1875 bcc_ptr += strnlen(user, 200);
1876 }
1877 *bcc_ptr = 0;
1878 bcc_ptr++;
1879 if (domain == NULL) {
1880 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1881 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1882 } else {
1883 strncpy(bcc_ptr, domain, 64);
1884 bcc_ptr += strnlen(domain, 64);
1885 *bcc_ptr = 0;
1886 bcc_ptr++;
1887 }
1888 strcpy(bcc_ptr, "Linux version ");
1889 bcc_ptr += strlen("Linux version ");
1890 strcpy(bcc_ptr, system_utsname.release);
1891 bcc_ptr += strlen(system_utsname.release) + 1;
1892 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1893 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1894 }
1895 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1896 smb_buffer->smb_buf_length += count;
1897 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1898
1899 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1900 &bytes_returned, 1);
1901 if (rc) {
1902/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1903 } else if ((smb_buffer_response->WordCount == 3)
1904 || (smb_buffer_response->WordCount == 4)) {
1905 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1906 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1907 if (action & GUEST_LOGIN)
1908 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1909 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1910 cFYI(1, ("UID = %d ", ses->Suid));
1911 /* response can have either 3 or 4 word count - Samba sends 3 */
1912 bcc_ptr = pByteArea(smb_buffer_response);
1913 if ((pSMBr->resp.hdr.WordCount == 3)
1914 || ((pSMBr->resp.hdr.WordCount == 4)
1915 && (blob_len < pSMBr->resp.ByteCount))) {
1916 if (pSMBr->resp.hdr.WordCount == 4)
1917 bcc_ptr += blob_len;
1918
1919 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1920 if ((long) (bcc_ptr) % 2) {
1921 remaining_words =
1922 (BCC(smb_buffer_response) - 1) /2;
1923 bcc_ptr++; /* Unicode strings must be word aligned */
1924 } else {
1925 remaining_words =
1926 BCC(smb_buffer_response) / 2;
1927 }
1928 len =
1929 UniStrnlen((wchar_t *) bcc_ptr,
1930 remaining_words - 1);
1931/* We look for obvious messed up bcc or strings in response so we do not go off
1932 the end since (at least) WIN2K and Windows XP have a major bug in not null
1933 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07001934 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
1935 if(ses->serverOS == NULL)
1936 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 cifs_strfromUCS_le(ses->serverOS,
1938 (wchar_t *)bcc_ptr, len,nls_codepage);
1939 bcc_ptr += 2 * (len + 1);
1940 remaining_words -= len + 1;
1941 ses->serverOS[2 * len] = 0;
1942 ses->serverOS[1 + (2 * len)] = 0;
1943 if (remaining_words > 0) {
1944 len = UniStrnlen((wchar_t *)bcc_ptr,
1945 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07001946 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
1947 if(ses->serverNOS == NULL)
1948 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 cifs_strfromUCS_le(ses->serverNOS,
1950 (wchar_t *)bcc_ptr,len,nls_codepage);
1951 bcc_ptr += 2 * (len + 1);
1952 ses->serverNOS[2 * len] = 0;
1953 ses->serverNOS[1 + (2 * len)] = 0;
1954 if(strncmp(ses->serverNOS,
1955 "NT LAN Manager 4",16) == 0) {
1956 cFYI(1,("NT4 server"));
1957 ses->flags |= CIFS_SES_NT4;
1958 }
1959 remaining_words -= len + 1;
1960 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07001961 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1963 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07001964 kcalloc(1, 2*(len+1),GFP_KERNEL);
1965 if(ses->serverDomain == NULL)
1966 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 cifs_strfromUCS_le(ses->serverDomain,
1968 (wchar_t *)bcc_ptr,len,nls_codepage);
1969 bcc_ptr += 2 * (len + 1);
1970 ses->serverDomain[2*len] = 0;
1971 ses->serverDomain[1+(2*len)] = 0;
1972 } /* else no more room so create dummy domain string */
1973 else
Steve French433dc242005-04-28 22:41:08 -07001974 ses->serverDomain =
1975 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07001977 /* if these kcallocs fail not much we
1978 can do, but better to not fail the
1979 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07001981 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07001983 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 }
1985 } else { /* ASCII */
1986 len = strnlen(bcc_ptr, 1024);
1987 if (((long) bcc_ptr + len) - (long)
1988 pByteArea(smb_buffer_response)
1989 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07001990 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
1991 if(ses->serverOS == NULL)
1992 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 strncpy(ses->serverOS,bcc_ptr, len);
1994
1995 bcc_ptr += len;
1996 bcc_ptr[0] = 0; /* null terminate the string */
1997 bcc_ptr++;
1998
1999 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002000 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2001 if(ses->serverNOS == NULL)
2002 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 strncpy(ses->serverNOS, bcc_ptr, len);
2004 bcc_ptr += len;
2005 bcc_ptr[0] = 0;
2006 bcc_ptr++;
2007
2008 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002009 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2010 if(ses->serverDomain == NULL)
2011 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 strncpy(ses->serverDomain, bcc_ptr, len);
2013 bcc_ptr += len;
2014 bcc_ptr[0] = 0;
2015 bcc_ptr++;
2016 } else
2017 cFYI(1,
2018 ("Variable field of length %d extends beyond end of smb ",
2019 len));
2020 }
2021 } else {
2022 cERROR(1,
2023 (" Security Blob Length extends beyond end of SMB"));
2024 }
2025 } else {
2026 cERROR(1,
2027 (" Invalid Word count %d: ",
2028 smb_buffer_response->WordCount));
2029 rc = -EIO;
2030 }
Steve French433dc242005-04-28 22:41:08 -07002031sesssetup_nomem: /* do not return an error on nomem for the info strings,
2032 since that could make reconnection harder, and
2033 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 if (smb_buffer)
2035 cifs_buf_release(smb_buffer);
2036
2037 return rc;
2038}
2039
2040static int
2041CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2042 char *SecurityBlob,int SecurityBlobLength,
2043 const struct nls_table *nls_codepage)
2044{
2045 struct smb_hdr *smb_buffer;
2046 struct smb_hdr *smb_buffer_response;
2047 SESSION_SETUP_ANDX *pSMB;
2048 SESSION_SETUP_ANDX *pSMBr;
2049 char *bcc_ptr;
2050 char *user;
2051 char *domain;
2052 int rc = 0;
2053 int remaining_words = 0;
2054 int bytes_returned = 0;
2055 int len;
2056 __u32 capabilities;
2057 __u16 count;
2058
2059 cFYI(1, ("In spnego sesssetup "));
2060 if(ses == NULL)
2061 return -EINVAL;
2062 user = ses->userName;
2063 domain = ses->domainName;
2064
2065 smb_buffer = cifs_buf_get();
2066 if (smb_buffer == NULL) {
2067 return -ENOMEM;
2068 }
2069 smb_buffer_response = smb_buffer;
2070 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2071
2072 /* send SMBsessionSetup here */
2073 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2074 NULL /* no tCon exists yet */ , 12 /* wct */ );
2075 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2076 pSMB->req.AndXCommand = 0xFF;
2077 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2078 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2079
2080 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2081 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2082
2083 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2084 CAP_EXTENDED_SECURITY;
2085 if (ses->capabilities & CAP_UNICODE) {
2086 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2087 capabilities |= CAP_UNICODE;
2088 }
2089 if (ses->capabilities & CAP_STATUS32) {
2090 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2091 capabilities |= CAP_STATUS32;
2092 }
2093 if (ses->capabilities & CAP_DFS) {
2094 smb_buffer->Flags2 |= SMBFLG2_DFS;
2095 capabilities |= CAP_DFS;
2096 }
2097 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2098
2099 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2100 bcc_ptr = pByteArea(smb_buffer);
2101 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2102 bcc_ptr += SecurityBlobLength;
2103
2104 if (ses->capabilities & CAP_UNICODE) {
2105 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2106 *bcc_ptr = 0;
2107 bcc_ptr++;
2108 }
2109 bytes_returned =
2110 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2111 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2112 bcc_ptr += 2; /* trailing null */
2113 if (domain == NULL)
2114 bytes_returned =
2115 cifs_strtoUCS((wchar_t *) bcc_ptr,
2116 "CIFS_LINUX_DOM", 32, nls_codepage);
2117 else
2118 bytes_returned =
2119 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2120 nls_codepage);
2121 bcc_ptr += 2 * bytes_returned;
2122 bcc_ptr += 2;
2123 bytes_returned =
2124 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2125 32, nls_codepage);
2126 bcc_ptr += 2 * bytes_returned;
2127 bytes_returned =
2128 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2129 nls_codepage);
2130 bcc_ptr += 2 * bytes_returned;
2131 bcc_ptr += 2;
2132 bytes_returned =
2133 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2134 64, nls_codepage);
2135 bcc_ptr += 2 * bytes_returned;
2136 bcc_ptr += 2;
2137 } else {
2138 strncpy(bcc_ptr, user, 200);
2139 bcc_ptr += strnlen(user, 200);
2140 *bcc_ptr = 0;
2141 bcc_ptr++;
2142 if (domain == NULL) {
2143 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2144 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2145 } else {
2146 strncpy(bcc_ptr, domain, 64);
2147 bcc_ptr += strnlen(domain, 64);
2148 *bcc_ptr = 0;
2149 bcc_ptr++;
2150 }
2151 strcpy(bcc_ptr, "Linux version ");
2152 bcc_ptr += strlen("Linux version ");
2153 strcpy(bcc_ptr, system_utsname.release);
2154 bcc_ptr += strlen(system_utsname.release) + 1;
2155 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2156 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2157 }
2158 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2159 smb_buffer->smb_buf_length += count;
2160 pSMB->req.ByteCount = cpu_to_le16(count);
2161
2162 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2163 &bytes_returned, 1);
2164 if (rc) {
2165/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2166 } else if ((smb_buffer_response->WordCount == 3)
2167 || (smb_buffer_response->WordCount == 4)) {
2168 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2169 __u16 blob_len =
2170 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2171 if (action & GUEST_LOGIN)
2172 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2173 if (ses) {
2174 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2175 cFYI(1, ("UID = %d ", ses->Suid));
2176 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2177
2178 /* BB Fix below to make endian neutral !! */
2179
2180 if ((pSMBr->resp.hdr.WordCount == 3)
2181 || ((pSMBr->resp.hdr.WordCount == 4)
2182 && (blob_len <
2183 pSMBr->resp.ByteCount))) {
2184 if (pSMBr->resp.hdr.WordCount == 4) {
2185 bcc_ptr +=
2186 blob_len;
2187 cFYI(1,
2188 ("Security Blob Length %d ",
2189 blob_len));
2190 }
2191
2192 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2193 if ((long) (bcc_ptr) % 2) {
2194 remaining_words =
2195 (BCC(smb_buffer_response)
2196 - 1) / 2;
2197 bcc_ptr++; /* Unicode strings must be word aligned */
2198 } else {
2199 remaining_words =
2200 BCC
2201 (smb_buffer_response) / 2;
2202 }
2203 len =
2204 UniStrnlen((wchar_t *) bcc_ptr,
2205 remaining_words - 1);
2206/* We look for obvious messed up bcc or strings in response so we do not go off
2207 the end since (at least) WIN2K and Windows XP have a major bug in not null
2208 terminating last Unicode string in response */
2209 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002210 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 cifs_strfromUCS_le(ses->serverOS,
2212 (wchar_t *)
2213 bcc_ptr, len,
2214 nls_codepage);
2215 bcc_ptr += 2 * (len + 1);
2216 remaining_words -= len + 1;
2217 ses->serverOS[2 * len] = 0;
2218 ses->serverOS[1 + (2 * len)] = 0;
2219 if (remaining_words > 0) {
2220 len = UniStrnlen((wchar_t *)bcc_ptr,
2221 remaining_words
2222 - 1);
2223 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002224 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 GFP_KERNEL);
2226 cifs_strfromUCS_le(ses->serverNOS,
2227 (wchar_t *)bcc_ptr,
2228 len,
2229 nls_codepage);
2230 bcc_ptr += 2 * (len + 1);
2231 ses->serverNOS[2 * len] = 0;
2232 ses->serverNOS[1 + (2 * len)] = 0;
2233 remaining_words -= len + 1;
2234 if (remaining_words > 0) {
2235 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2236 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002237 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 cifs_strfromUCS_le(ses->serverDomain,
2239 (wchar_t *)bcc_ptr,
2240 len,
2241 nls_codepage);
2242 bcc_ptr += 2*(len+1);
2243 ses->serverDomain[2*len] = 0;
2244 ses->serverDomain[1+(2*len)] = 0;
2245 } /* else no more room so create dummy domain string */
2246 else
2247 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002248 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002250 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2251 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 }
2253 } else { /* ASCII */
2254
2255 len = strnlen(bcc_ptr, 1024);
2256 if (((long) bcc_ptr + len) - (long)
2257 pByteArea(smb_buffer_response)
2258 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002259 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 strncpy(ses->serverOS, bcc_ptr, len);
2261
2262 bcc_ptr += len;
2263 bcc_ptr[0] = 0; /* null terminate the string */
2264 bcc_ptr++;
2265
2266 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002267 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 strncpy(ses->serverNOS, bcc_ptr, len);
2269 bcc_ptr += len;
2270 bcc_ptr[0] = 0;
2271 bcc_ptr++;
2272
2273 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002274 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 strncpy(ses->serverDomain, bcc_ptr, len);
2276 bcc_ptr += len;
2277 bcc_ptr[0] = 0;
2278 bcc_ptr++;
2279 } else
2280 cFYI(1,
2281 ("Variable field of length %d extends beyond end of smb ",
2282 len));
2283 }
2284 } else {
2285 cERROR(1,
2286 (" Security Blob Length extends beyond end of SMB"));
2287 }
2288 } else {
2289 cERROR(1, ("No session structure passed in."));
2290 }
2291 } else {
2292 cERROR(1,
2293 (" Invalid Word count %d: ",
2294 smb_buffer_response->WordCount));
2295 rc = -EIO;
2296 }
2297
2298 if (smb_buffer)
2299 cifs_buf_release(smb_buffer);
2300
2301 return rc;
2302}
2303
2304static int
2305CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2306 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2307 const struct nls_table *nls_codepage)
2308{
2309 struct smb_hdr *smb_buffer;
2310 struct smb_hdr *smb_buffer_response;
2311 SESSION_SETUP_ANDX *pSMB;
2312 SESSION_SETUP_ANDX *pSMBr;
2313 char *bcc_ptr;
2314 char *domain;
2315 int rc = 0;
2316 int remaining_words = 0;
2317 int bytes_returned = 0;
2318 int len;
2319 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2320 PNEGOTIATE_MESSAGE SecurityBlob;
2321 PCHALLENGE_MESSAGE SecurityBlob2;
2322 __u32 negotiate_flags, capabilities;
2323 __u16 count;
2324
2325 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2326 if(ses == NULL)
2327 return -EINVAL;
2328 domain = ses->domainName;
2329 *pNTLMv2_flag = FALSE;
2330 smb_buffer = cifs_buf_get();
2331 if (smb_buffer == NULL) {
2332 return -ENOMEM;
2333 }
2334 smb_buffer_response = smb_buffer;
2335 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2336 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2337
2338 /* send SMBsessionSetup here */
2339 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2340 NULL /* no tCon exists yet */ , 12 /* wct */ );
2341 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2342 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2343
2344 pSMB->req.AndXCommand = 0xFF;
2345 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2346 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2347
2348 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2349 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2350
2351 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2352 CAP_EXTENDED_SECURITY;
2353 if (ses->capabilities & CAP_UNICODE) {
2354 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2355 capabilities |= CAP_UNICODE;
2356 }
2357 if (ses->capabilities & CAP_STATUS32) {
2358 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2359 capabilities |= CAP_STATUS32;
2360 }
2361 if (ses->capabilities & CAP_DFS) {
2362 smb_buffer->Flags2 |= SMBFLG2_DFS;
2363 capabilities |= CAP_DFS;
2364 }
2365 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2366
2367 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2368 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2369 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2370 SecurityBlob->MessageType = NtLmNegotiate;
2371 negotiate_flags =
2372 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2373 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2374 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2375 if(sign_CIFS_PDUs)
2376 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2377 if(ntlmv2_support)
2378 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2379 /* setup pointers to domain name and workstation name */
2380 bcc_ptr += SecurityBlobLength;
2381
2382 SecurityBlob->WorkstationName.Buffer = 0;
2383 SecurityBlob->WorkstationName.Length = 0;
2384 SecurityBlob->WorkstationName.MaximumLength = 0;
2385
2386 if (domain == NULL) {
2387 SecurityBlob->DomainName.Buffer = 0;
2388 SecurityBlob->DomainName.Length = 0;
2389 SecurityBlob->DomainName.MaximumLength = 0;
2390 } else {
2391 __u16 len;
2392 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2393 strncpy(bcc_ptr, domain, 63);
2394 len = strnlen(domain, 64);
2395 SecurityBlob->DomainName.MaximumLength =
2396 cpu_to_le16(len);
2397 SecurityBlob->DomainName.Buffer =
2398 cpu_to_le32((long) &SecurityBlob->
2399 DomainString -
2400 (long) &SecurityBlob->Signature);
2401 bcc_ptr += len;
2402 SecurityBlobLength += len;
2403 SecurityBlob->DomainName.Length =
2404 cpu_to_le16(len);
2405 }
2406 if (ses->capabilities & CAP_UNICODE) {
2407 if ((long) bcc_ptr % 2) {
2408 *bcc_ptr = 0;
2409 bcc_ptr++;
2410 }
2411
2412 bytes_returned =
2413 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2414 32, nls_codepage);
2415 bcc_ptr += 2 * bytes_returned;
2416 bytes_returned =
2417 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2418 nls_codepage);
2419 bcc_ptr += 2 * bytes_returned;
2420 bcc_ptr += 2; /* null terminate Linux version */
2421 bytes_returned =
2422 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2423 64, nls_codepage);
2424 bcc_ptr += 2 * bytes_returned;
2425 *(bcc_ptr + 1) = 0;
2426 *(bcc_ptr + 2) = 0;
2427 bcc_ptr += 2; /* null terminate network opsys string */
2428 *(bcc_ptr + 1) = 0;
2429 *(bcc_ptr + 2) = 0;
2430 bcc_ptr += 2; /* null domain */
2431 } else { /* ASCII */
2432 strcpy(bcc_ptr, "Linux version ");
2433 bcc_ptr += strlen("Linux version ");
2434 strcpy(bcc_ptr, system_utsname.release);
2435 bcc_ptr += strlen(system_utsname.release) + 1;
2436 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2437 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2438 bcc_ptr++; /* empty domain field */
2439 *bcc_ptr = 0;
2440 }
2441 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2442 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2443 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2444 smb_buffer->smb_buf_length += count;
2445 pSMB->req.ByteCount = cpu_to_le16(count);
2446
2447 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2448 &bytes_returned, 1);
2449
2450 if (smb_buffer_response->Status.CifsError ==
2451 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2452 rc = 0;
2453
2454 if (rc) {
2455/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2456 } else if ((smb_buffer_response->WordCount == 3)
2457 || (smb_buffer_response->WordCount == 4)) {
2458 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2459 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2460
2461 if (action & GUEST_LOGIN)
2462 cFYI(1, (" Guest login"));
2463 /* Do we want to set anything in SesInfo struct when guest login? */
2464
2465 bcc_ptr = pByteArea(smb_buffer_response);
2466 /* response can have either 3 or 4 word count - Samba sends 3 */
2467
2468 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2469 if (SecurityBlob2->MessageType != NtLmChallenge) {
2470 cFYI(1,
2471 ("Unexpected NTLMSSP message type received %d",
2472 SecurityBlob2->MessageType));
2473 } else if (ses) {
2474 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2475 cFYI(1, ("UID = %d ", ses->Suid));
2476 if ((pSMBr->resp.hdr.WordCount == 3)
2477 || ((pSMBr->resp.hdr.WordCount == 4)
2478 && (blob_len <
2479 pSMBr->resp.ByteCount))) {
2480
2481 if (pSMBr->resp.hdr.WordCount == 4) {
2482 bcc_ptr += blob_len;
2483 cFYI(1,
2484 ("Security Blob Length %d ",
2485 blob_len));
2486 }
2487
2488 cFYI(1, ("NTLMSSP Challenge rcvd "));
2489
2490 memcpy(ses->server->cryptKey,
2491 SecurityBlob2->Challenge,
2492 CIFS_CRYPTO_KEY_SIZE);
2493 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2494 *pNTLMv2_flag = TRUE;
2495
2496 if((SecurityBlob2->NegotiateFlags &
2497 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2498 || (sign_CIFS_PDUs > 1))
2499 ses->server->secMode |=
2500 SECMODE_SIGN_REQUIRED;
2501 if ((SecurityBlob2->NegotiateFlags &
2502 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2503 ses->server->secMode |=
2504 SECMODE_SIGN_ENABLED;
2505
2506 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2507 if ((long) (bcc_ptr) % 2) {
2508 remaining_words =
2509 (BCC(smb_buffer_response)
2510 - 1) / 2;
2511 bcc_ptr++; /* Unicode strings must be word aligned */
2512 } else {
2513 remaining_words =
2514 BCC
2515 (smb_buffer_response) / 2;
2516 }
2517 len =
2518 UniStrnlen((wchar_t *) bcc_ptr,
2519 remaining_words - 1);
2520/* We look for obvious messed up bcc or strings in response so we do not go off
2521 the end since (at least) WIN2K and Windows XP have a major bug in not null
2522 terminating last Unicode string in response */
2523 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002524 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 cifs_strfromUCS_le(ses->serverOS,
2526 (wchar_t *)
2527 bcc_ptr, len,
2528 nls_codepage);
2529 bcc_ptr += 2 * (len + 1);
2530 remaining_words -= len + 1;
2531 ses->serverOS[2 * len] = 0;
2532 ses->serverOS[1 + (2 * len)] = 0;
2533 if (remaining_words > 0) {
2534 len = UniStrnlen((wchar_t *)
2535 bcc_ptr,
2536 remaining_words
2537 - 1);
2538 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002539 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 GFP_KERNEL);
2541 cifs_strfromUCS_le(ses->
2542 serverNOS,
2543 (wchar_t *)
2544 bcc_ptr,
2545 len,
2546 nls_codepage);
2547 bcc_ptr += 2 * (len + 1);
2548 ses->serverNOS[2 * len] = 0;
2549 ses->serverNOS[1 +
2550 (2 * len)] = 0;
2551 remaining_words -= len + 1;
2552 if (remaining_words > 0) {
2553 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2554 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2555 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002556 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 (len +
2558 1),
2559 GFP_KERNEL);
2560 cifs_strfromUCS_le
2561 (ses->
2562 serverDomain,
2563 (wchar_t *)
2564 bcc_ptr, len,
2565 nls_codepage);
2566 bcc_ptr +=
2567 2 * (len + 1);
2568 ses->
2569 serverDomain[2
2570 * len]
2571 = 0;
2572 ses->
2573 serverDomain[1
2574 +
2575 (2
2576 *
2577 len)]
2578 = 0;
2579 } /* else no more room so create dummy domain string */
2580 else
2581 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002582 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 GFP_KERNEL);
2584 } else { /* no room so create dummy domain and NOS string */
2585 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002586 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002588 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 }
2590 } else { /* ASCII */
2591 len = strnlen(bcc_ptr, 1024);
2592 if (((long) bcc_ptr + len) - (long)
2593 pByteArea(smb_buffer_response)
2594 <= BCC(smb_buffer_response)) {
2595 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002596 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 GFP_KERNEL);
2598 strncpy(ses->serverOS,
2599 bcc_ptr, len);
2600
2601 bcc_ptr += len;
2602 bcc_ptr[0] = 0; /* null terminate string */
2603 bcc_ptr++;
2604
2605 len = strnlen(bcc_ptr, 1024);
2606 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002607 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 GFP_KERNEL);
2609 strncpy(ses->serverNOS, bcc_ptr, len);
2610 bcc_ptr += len;
2611 bcc_ptr[0] = 0;
2612 bcc_ptr++;
2613
2614 len = strnlen(bcc_ptr, 1024);
2615 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002616 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 GFP_KERNEL);
2618 strncpy(ses->serverDomain, bcc_ptr, len);
2619 bcc_ptr += len;
2620 bcc_ptr[0] = 0;
2621 bcc_ptr++;
2622 } else
2623 cFYI(1,
2624 ("Variable field of length %d extends beyond end of smb ",
2625 len));
2626 }
2627 } else {
2628 cERROR(1,
2629 (" Security Blob Length extends beyond end of SMB"));
2630 }
2631 } else {
2632 cERROR(1, ("No session structure passed in."));
2633 }
2634 } else {
2635 cERROR(1,
2636 (" Invalid Word count %d: ",
2637 smb_buffer_response->WordCount));
2638 rc = -EIO;
2639 }
2640
2641 if (smb_buffer)
2642 cifs_buf_release(smb_buffer);
2643
2644 return rc;
2645}
2646static int
2647CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2648 char *ntlm_session_key, int ntlmv2_flag,
2649 const struct nls_table *nls_codepage)
2650{
2651 struct smb_hdr *smb_buffer;
2652 struct smb_hdr *smb_buffer_response;
2653 SESSION_SETUP_ANDX *pSMB;
2654 SESSION_SETUP_ANDX *pSMBr;
2655 char *bcc_ptr;
2656 char *user;
2657 char *domain;
2658 int rc = 0;
2659 int remaining_words = 0;
2660 int bytes_returned = 0;
2661 int len;
2662 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2663 PAUTHENTICATE_MESSAGE SecurityBlob;
2664 __u32 negotiate_flags, capabilities;
2665 __u16 count;
2666
2667 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2668 if(ses == NULL)
2669 return -EINVAL;
2670 user = ses->userName;
2671 domain = ses->domainName;
2672 smb_buffer = cifs_buf_get();
2673 if (smb_buffer == NULL) {
2674 return -ENOMEM;
2675 }
2676 smb_buffer_response = smb_buffer;
2677 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2678 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2679
2680 /* send SMBsessionSetup here */
2681 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2682 NULL /* no tCon exists yet */ , 12 /* wct */ );
2683 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2684 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2685 pSMB->req.AndXCommand = 0xFF;
2686 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2687 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2688
2689 pSMB->req.hdr.Uid = ses->Suid;
2690
2691 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2692 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2693
2694 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2695 CAP_EXTENDED_SECURITY;
2696 if (ses->capabilities & CAP_UNICODE) {
2697 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2698 capabilities |= CAP_UNICODE;
2699 }
2700 if (ses->capabilities & CAP_STATUS32) {
2701 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2702 capabilities |= CAP_STATUS32;
2703 }
2704 if (ses->capabilities & CAP_DFS) {
2705 smb_buffer->Flags2 |= SMBFLG2_DFS;
2706 capabilities |= CAP_DFS;
2707 }
2708 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2709
2710 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2711 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2712 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2713 SecurityBlob->MessageType = NtLmAuthenticate;
2714 bcc_ptr += SecurityBlobLength;
2715 negotiate_flags =
2716 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2717 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2718 0x80000000 | NTLMSSP_NEGOTIATE_128;
2719 if(sign_CIFS_PDUs)
2720 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2721 if(ntlmv2_flag)
2722 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2723
2724/* setup pointers to domain name and workstation name */
2725
2726 SecurityBlob->WorkstationName.Buffer = 0;
2727 SecurityBlob->WorkstationName.Length = 0;
2728 SecurityBlob->WorkstationName.MaximumLength = 0;
2729 SecurityBlob->SessionKey.Length = 0;
2730 SecurityBlob->SessionKey.MaximumLength = 0;
2731 SecurityBlob->SessionKey.Buffer = 0;
2732
2733 SecurityBlob->LmChallengeResponse.Length = 0;
2734 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2735 SecurityBlob->LmChallengeResponse.Buffer = 0;
2736
2737 SecurityBlob->NtChallengeResponse.Length =
2738 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2739 SecurityBlob->NtChallengeResponse.MaximumLength =
2740 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2741 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2742 SecurityBlob->NtChallengeResponse.Buffer =
2743 cpu_to_le32(SecurityBlobLength);
2744 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2745 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2746
2747 if (ses->capabilities & CAP_UNICODE) {
2748 if (domain == NULL) {
2749 SecurityBlob->DomainName.Buffer = 0;
2750 SecurityBlob->DomainName.Length = 0;
2751 SecurityBlob->DomainName.MaximumLength = 0;
2752 } else {
2753 __u16 len =
2754 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2755 nls_codepage);
2756 len *= 2;
2757 SecurityBlob->DomainName.MaximumLength =
2758 cpu_to_le16(len);
2759 SecurityBlob->DomainName.Buffer =
2760 cpu_to_le32(SecurityBlobLength);
2761 bcc_ptr += len;
2762 SecurityBlobLength += len;
2763 SecurityBlob->DomainName.Length =
2764 cpu_to_le16(len);
2765 }
2766 if (user == NULL) {
2767 SecurityBlob->UserName.Buffer = 0;
2768 SecurityBlob->UserName.Length = 0;
2769 SecurityBlob->UserName.MaximumLength = 0;
2770 } else {
2771 __u16 len =
2772 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2773 nls_codepage);
2774 len *= 2;
2775 SecurityBlob->UserName.MaximumLength =
2776 cpu_to_le16(len);
2777 SecurityBlob->UserName.Buffer =
2778 cpu_to_le32(SecurityBlobLength);
2779 bcc_ptr += len;
2780 SecurityBlobLength += len;
2781 SecurityBlob->UserName.Length =
2782 cpu_to_le16(len);
2783 }
2784
2785 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2786 SecurityBlob->WorkstationName.Length *= 2;
2787 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2788 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2789 bcc_ptr += SecurityBlob->WorkstationName.Length;
2790 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2791 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2792
2793 if ((long) bcc_ptr % 2) {
2794 *bcc_ptr = 0;
2795 bcc_ptr++;
2796 }
2797 bytes_returned =
2798 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2799 32, nls_codepage);
2800 bcc_ptr += 2 * bytes_returned;
2801 bytes_returned =
2802 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2803 nls_codepage);
2804 bcc_ptr += 2 * bytes_returned;
2805 bcc_ptr += 2; /* null term version string */
2806 bytes_returned =
2807 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2808 64, nls_codepage);
2809 bcc_ptr += 2 * bytes_returned;
2810 *(bcc_ptr + 1) = 0;
2811 *(bcc_ptr + 2) = 0;
2812 bcc_ptr += 2; /* null terminate network opsys string */
2813 *(bcc_ptr + 1) = 0;
2814 *(bcc_ptr + 2) = 0;
2815 bcc_ptr += 2; /* null domain */
2816 } else { /* ASCII */
2817 if (domain == NULL) {
2818 SecurityBlob->DomainName.Buffer = 0;
2819 SecurityBlob->DomainName.Length = 0;
2820 SecurityBlob->DomainName.MaximumLength = 0;
2821 } else {
2822 __u16 len;
2823 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2824 strncpy(bcc_ptr, domain, 63);
2825 len = strnlen(domain, 64);
2826 SecurityBlob->DomainName.MaximumLength =
2827 cpu_to_le16(len);
2828 SecurityBlob->DomainName.Buffer =
2829 cpu_to_le32(SecurityBlobLength);
2830 bcc_ptr += len;
2831 SecurityBlobLength += len;
2832 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2833 }
2834 if (user == NULL) {
2835 SecurityBlob->UserName.Buffer = 0;
2836 SecurityBlob->UserName.Length = 0;
2837 SecurityBlob->UserName.MaximumLength = 0;
2838 } else {
2839 __u16 len;
2840 strncpy(bcc_ptr, user, 63);
2841 len = strnlen(user, 64);
2842 SecurityBlob->UserName.MaximumLength =
2843 cpu_to_le16(len);
2844 SecurityBlob->UserName.Buffer =
2845 cpu_to_le32(SecurityBlobLength);
2846 bcc_ptr += len;
2847 SecurityBlobLength += len;
2848 SecurityBlob->UserName.Length = cpu_to_le16(len);
2849 }
2850 /* BB fill in our workstation name if known BB */
2851
2852 strcpy(bcc_ptr, "Linux version ");
2853 bcc_ptr += strlen("Linux version ");
2854 strcpy(bcc_ptr, system_utsname.release);
2855 bcc_ptr += strlen(system_utsname.release) + 1;
2856 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2857 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2858 bcc_ptr++; /* null domain */
2859 *bcc_ptr = 0;
2860 }
2861 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2862 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2863 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2864 smb_buffer->smb_buf_length += count;
2865 pSMB->req.ByteCount = cpu_to_le16(count);
2866
2867 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2868 &bytes_returned, 1);
2869 if (rc) {
2870/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2871 } else if ((smb_buffer_response->WordCount == 3)
2872 || (smb_buffer_response->WordCount == 4)) {
2873 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2874 __u16 blob_len =
2875 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2876 if (action & GUEST_LOGIN)
2877 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2878/* if(SecurityBlob2->MessageType != NtLm??){
2879 cFYI("Unexpected message type on auth response is %d "));
2880 } */
2881 if (ses) {
2882 cFYI(1,
2883 ("Does UID on challenge %d match auth response UID %d ",
2884 ses->Suid, smb_buffer_response->Uid));
2885 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2886 bcc_ptr = pByteArea(smb_buffer_response);
2887 /* response can have either 3 or 4 word count - Samba sends 3 */
2888 if ((pSMBr->resp.hdr.WordCount == 3)
2889 || ((pSMBr->resp.hdr.WordCount == 4)
2890 && (blob_len <
2891 pSMBr->resp.ByteCount))) {
2892 if (pSMBr->resp.hdr.WordCount == 4) {
2893 bcc_ptr +=
2894 blob_len;
2895 cFYI(1,
2896 ("Security Blob Length %d ",
2897 blob_len));
2898 }
2899
2900 cFYI(1,
2901 ("NTLMSSP response to Authenticate "));
2902
2903 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2904 if ((long) (bcc_ptr) % 2) {
2905 remaining_words =
2906 (BCC(smb_buffer_response)
2907 - 1) / 2;
2908 bcc_ptr++; /* Unicode strings must be word aligned */
2909 } else {
2910 remaining_words = BCC(smb_buffer_response) / 2;
2911 }
2912 len =
2913 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2914/* We look for obvious messed up bcc or strings in response so we do not go off
2915 the end since (at least) WIN2K and Windows XP have a major bug in not null
2916 terminating last Unicode string in response */
2917 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002918 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 cifs_strfromUCS_le(ses->serverOS,
2920 (wchar_t *)
2921 bcc_ptr, len,
2922 nls_codepage);
2923 bcc_ptr += 2 * (len + 1);
2924 remaining_words -= len + 1;
2925 ses->serverOS[2 * len] = 0;
2926 ses->serverOS[1 + (2 * len)] = 0;
2927 if (remaining_words > 0) {
2928 len = UniStrnlen((wchar_t *)
2929 bcc_ptr,
2930 remaining_words
2931 - 1);
2932 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002933 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 GFP_KERNEL);
2935 cifs_strfromUCS_le(ses->
2936 serverNOS,
2937 (wchar_t *)
2938 bcc_ptr,
2939 len,
2940 nls_codepage);
2941 bcc_ptr += 2 * (len + 1);
2942 ses->serverNOS[2 * len] = 0;
2943 ses->serverNOS[1+(2*len)] = 0;
2944 remaining_words -= len + 1;
2945 if (remaining_words > 0) {
2946 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2947 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2948 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002949 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 (len +
2951 1),
2952 GFP_KERNEL);
2953 cifs_strfromUCS_le
2954 (ses->
2955 serverDomain,
2956 (wchar_t *)
2957 bcc_ptr, len,
2958 nls_codepage);
2959 bcc_ptr +=
2960 2 * (len + 1);
2961 ses->
2962 serverDomain[2
2963 * len]
2964 = 0;
2965 ses->
2966 serverDomain[1
2967 +
2968 (2
2969 *
2970 len)]
2971 = 0;
2972 } /* else no more room so create dummy domain string */
2973 else
Steve French433dc242005-04-28 22:41:08 -07002974 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002976 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2977 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 }
2979 } else { /* ASCII */
2980 len = strnlen(bcc_ptr, 1024);
2981 if (((long) bcc_ptr + len) -
2982 (long) pByteArea(smb_buffer_response)
2983 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002984 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 strncpy(ses->serverOS,bcc_ptr, len);
2986
2987 bcc_ptr += len;
2988 bcc_ptr[0] = 0; /* null terminate the string */
2989 bcc_ptr++;
2990
2991 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002992 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 strncpy(ses->serverNOS, bcc_ptr, len);
2994 bcc_ptr += len;
2995 bcc_ptr[0] = 0;
2996 bcc_ptr++;
2997
2998 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002999 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 strncpy(ses->serverDomain, bcc_ptr, len);
3001 bcc_ptr += len;
3002 bcc_ptr[0] = 0;
3003 bcc_ptr++;
3004 } else
3005 cFYI(1,
3006 ("Variable field of length %d extends beyond end of smb ",
3007 len));
3008 }
3009 } else {
3010 cERROR(1,
3011 (" Security Blob Length extends beyond end of SMB"));
3012 }
3013 } else {
3014 cERROR(1, ("No session structure passed in."));
3015 }
3016 } else {
3017 cERROR(1,
3018 (" Invalid Word count %d: ",
3019 smb_buffer_response->WordCount));
3020 rc = -EIO;
3021 }
3022
3023 if (smb_buffer)
3024 cifs_buf_release(smb_buffer);
3025
3026 return rc;
3027}
3028
3029int
3030CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3031 const char *tree, struct cifsTconInfo *tcon,
3032 const struct nls_table *nls_codepage)
3033{
3034 struct smb_hdr *smb_buffer;
3035 struct smb_hdr *smb_buffer_response;
3036 TCONX_REQ *pSMB;
3037 TCONX_RSP *pSMBr;
3038 unsigned char *bcc_ptr;
3039 int rc = 0;
3040 int length;
3041 __u16 count;
3042
3043 if (ses == NULL)
3044 return -EIO;
3045
3046 smb_buffer = cifs_buf_get();
3047 if (smb_buffer == NULL) {
3048 return -ENOMEM;
3049 }
3050 smb_buffer_response = smb_buffer;
3051
3052 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3053 NULL /*no tid */ , 4 /*wct */ );
3054 smb_buffer->Uid = ses->Suid;
3055 pSMB = (TCONX_REQ *) smb_buffer;
3056 pSMBr = (TCONX_RSP *) smb_buffer_response;
3057
3058 pSMB->AndXCommand = 0xFF;
3059 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3060 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3061 bcc_ptr = &pSMB->Password[0];
3062 bcc_ptr++; /* skip password */
3063
3064 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3065 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3066
3067 if (ses->capabilities & CAP_STATUS32) {
3068 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3069 }
3070 if (ses->capabilities & CAP_DFS) {
3071 smb_buffer->Flags2 |= SMBFLG2_DFS;
3072 }
3073 if (ses->capabilities & CAP_UNICODE) {
3074 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3075 length =
3076 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3077 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3078 bcc_ptr += 2; /* skip trailing null */
3079 } else { /* ASCII */
3080
3081 strcpy(bcc_ptr, tree);
3082 bcc_ptr += strlen(tree) + 1;
3083 }
3084 strcpy(bcc_ptr, "?????");
3085 bcc_ptr += strlen("?????");
3086 bcc_ptr += 1;
3087 count = bcc_ptr - &pSMB->Password[0];
3088 pSMB->hdr.smb_buf_length += count;
3089 pSMB->ByteCount = cpu_to_le16(count);
3090
3091 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3092
3093 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3094 /* above now done in SendReceive */
3095 if ((rc == 0) && (tcon != NULL)) {
3096 tcon->tidStatus = CifsGood;
3097 tcon->tid = smb_buffer_response->Tid;
3098 bcc_ptr = pByteArea(smb_buffer_response);
3099 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3100 /* skip service field (NB: this field is always ASCII) */
3101 bcc_ptr += length + 1;
3102 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3103 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3104 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3105 if ((bcc_ptr + (2 * length)) -
3106 pByteArea(smb_buffer_response) <=
3107 BCC(smb_buffer_response)) {
3108 if(tcon->nativeFileSystem)
3109 kfree(tcon->nativeFileSystem);
3110 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003111 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 cifs_strfromUCS_le(tcon->nativeFileSystem,
3113 (wchar_t *) bcc_ptr,
3114 length, nls_codepage);
3115 bcc_ptr += 2 * length;
3116 bcc_ptr[0] = 0; /* null terminate the string */
3117 bcc_ptr[1] = 0;
3118 bcc_ptr += 2;
3119 }
3120 /* else do not bother copying these informational fields */
3121 } else {
3122 length = strnlen(bcc_ptr, 1024);
3123 if ((bcc_ptr + length) -
3124 pByteArea(smb_buffer_response) <=
3125 BCC(smb_buffer_response)) {
3126 if(tcon->nativeFileSystem)
3127 kfree(tcon->nativeFileSystem);
3128 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003129 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 strncpy(tcon->nativeFileSystem, bcc_ptr,
3131 length);
3132 }
3133 /* else do not bother copying these informational fields */
3134 }
3135 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3136 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3137 } else if ((rc == 0) && tcon == NULL) {
3138 /* all we need to save for IPC$ connection */
3139 ses->ipc_tid = smb_buffer_response->Tid;
3140 }
3141
3142 if (smb_buffer)
3143 cifs_buf_release(smb_buffer);
3144 return rc;
3145}
3146
3147int
3148cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3149{
3150 int rc = 0;
3151 int xid;
3152 struct cifsSesInfo *ses = NULL;
3153 struct task_struct *cifsd_task;
3154
3155 xid = GetXid();
3156
3157 if (cifs_sb->tcon) {
3158 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3159 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3160 if (rc == -EBUSY) {
3161 FreeXid(xid);
3162 return 0;
3163 }
3164 tconInfoFree(cifs_sb->tcon);
3165 if ((ses) && (ses->server)) {
3166 /* save off task so we do not refer to ses later */
3167 cifsd_task = ses->server->tsk;
3168 cFYI(1, ("About to do SMBLogoff "));
3169 rc = CIFSSMBLogoff(xid, ses);
3170 if (rc == -EBUSY) {
3171 FreeXid(xid);
3172 return 0;
3173 } else if (rc == -ESHUTDOWN) {
3174 cFYI(1,("Waking up socket by sending it signal"));
3175 if(cifsd_task)
3176 send_sig(SIGKILL,cifsd_task,1);
3177 rc = 0;
3178 } /* else - we have an smb session
3179 left on this socket do not kill cifsd */
3180 } else
3181 cFYI(1, ("No session or bad tcon"));
3182 }
3183
3184 cifs_sb->tcon = NULL;
3185 if (ses) {
3186 set_current_state(TASK_INTERRUPTIBLE);
3187 schedule_timeout(HZ / 2);
3188 }
3189 if (ses)
3190 sesInfoFree(ses);
3191
3192 FreeXid(xid);
3193 return rc; /* BB check if we should always return zero here */
3194}
3195
3196int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3197 struct nls_table * nls_info)
3198{
3199 int rc = 0;
3200 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3201 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003202 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
3204 /* what if server changes its buffer size after dropping the session? */
3205 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3206 rc = CIFSSMBNegotiate(xid, pSesInfo);
3207 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3208 rc = CIFSSMBNegotiate(xid, pSesInfo);
3209 if(rc == -EAGAIN)
3210 rc = -EHOSTDOWN;
3211 }
3212 if(rc == 0) {
3213 spin_lock(&GlobalMid_Lock);
3214 if(pSesInfo->server->tcpStatus != CifsExiting)
3215 pSesInfo->server->tcpStatus = CifsGood;
3216 else
3217 rc = -EHOSTDOWN;
3218 spin_unlock(&GlobalMid_Lock);
3219
3220 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003221 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 }
3223 if (!rc) {
3224 pSesInfo->capabilities = pSesInfo->server->capabilities;
3225 if(linuxExtEnabled == 0)
3226 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003227 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3229 pSesInfo->server->secMode,
3230 pSesInfo->server->capabilities,
3231 pSesInfo->server->timeZone));
3232 if (extended_security
3233 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3234 && (pSesInfo->server->secType == NTLMSSP)) {
3235 cFYI(1, ("New style sesssetup "));
3236 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3237 NULL /* security blob */,
3238 0 /* blob length */,
3239 nls_info);
3240 } else if (extended_security
3241 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3242 && (pSesInfo->server->secType == RawNTLMSSP)) {
3243 cFYI(1, ("NTLMSSP sesssetup "));
3244 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3245 pSesInfo,
3246 &ntlmv2_flag,
3247 nls_info);
3248 if (!rc) {
3249 if(ntlmv2_flag) {
3250 char * v2_response;
3251 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3252 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3253 nls_info)) {
3254 rc = -ENOMEM;
3255 goto ss_err_exit;
3256 } else
3257 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3258 if(v2_response) {
3259 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003260 /* if(first_time)
3261 cifs_calculate_ntlmv2_mac_key(
3262 pSesInfo->server->mac_signing_key,
3263 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 kfree(v2_response);
3265 /* BB Put dummy sig in SessSetup PDU? */
3266 } else {
3267 rc = -ENOMEM;
3268 goto ss_err_exit;
3269 }
3270
3271 } else {
3272 SMBNTencrypt(pSesInfo->password,
3273 pSesInfo->server->cryptKey,
3274 ntlm_session_key);
3275
Steve Frenchad009ac2005-04-28 22:41:05 -07003276 if(first_time)
3277 cifs_calculate_mac_key(
3278 pSesInfo->server->mac_signing_key,
3279 ntlm_session_key,
3280 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 }
3282 /* for better security the weaker lanman hash not sent
3283 in AuthSessSetup so we no longer calculate it */
3284
3285 rc = CIFSNTLMSSPAuthSessSetup(xid,
3286 pSesInfo,
3287 ntlm_session_key,
3288 ntlmv2_flag,
3289 nls_info);
3290 }
3291 } else { /* old style NTLM 0.12 session setup */
3292 SMBNTencrypt(pSesInfo->password,
3293 pSesInfo->server->cryptKey,
3294 ntlm_session_key);
3295
Steve Frenchad009ac2005-04-28 22:41:05 -07003296 if(first_time)
3297 cifs_calculate_mac_key(
3298 pSesInfo->server->mac_signing_key,
3299 ntlm_session_key, pSesInfo->password);
3300
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 rc = CIFSSessSetup(xid, pSesInfo,
3302 ntlm_session_key, nls_info);
3303 }
3304 if (rc) {
3305 cERROR(1,("Send error in SessSetup = %d",rc));
3306 } else {
3307 cFYI(1,("CIFS Session Established successfully"));
3308 pSesInfo->status = CifsGood;
3309 }
3310 }
3311ss_err_exit:
3312 return rc;
3313}
3314