blob: a8d592bc33fe25c8bef37ff9d16353a30fa26aa7 [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) {
387 cFYI(1,("Reconnecting after server stopped responding"));
388 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) {
399 cFYI(1,("tcp session abended prematurely (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 }
410 cFYI(1,("Reconnecting after unexpected peek error %d",length));
411 cifs_reconnect(server);
412 csocket = server->ssocket;
413 wake_up(&server->response_q);
414 continue;
Steve French46810cb2005-04-28 22:41:09 -0700415 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 cFYI(1,
417 ("Frame less than four bytes received %d bytes long.",
418 length));
419 cifs_reconnect(server);
420 csocket = server->ssocket;
421 wake_up(&server->response_q);
422 continue;
423 }
Steve French67010fb2005-04-28 22:41:09 -0700424
Steve French46810cb2005-04-28 22:41:09 -0700425 /* the right amount was read from socket - 4 bytes */
426
427 pdu_length = ntohl(smb_buffer->smb_buf_length);
428 cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
429
430 temp = (char *) smb_buffer;
431 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700432 continue;
Steve French46810cb2005-04-28 22:41:09 -0700433 } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700434 cFYI(1,("Good RFC 1002 session rsp"));
435 continue;
Steve French46810cb2005-04-28 22:41:09 -0700436 } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
437 /* we get this from Windows 98 instead of
438 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700439 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
440 temp[4]));
Steve French46810cb2005-04-28 22:41:09 -0700441 if(server->tcpStatus == CifsNew) {
442 /* if nack on negprot (rather than
443 ret of smb negprot error) reconnecting
444 not going to help, ret error to mount */
445 break;
446 } else {
447 /* give server a second to
448 clean up before reconnect attempt */
449 msleep(1000);
450 /* always try 445 first on reconnect
451 since we get NACK on some if we ever
452 connected to port 139 (the NACK is
453 since we do not begin with RFC1001
454 session initialize frame) */
455 server->addr.sockAddr.sin_port =
456 htons(CIFS_PORT);
457 cifs_reconnect(server);
458 csocket = server->ssocket;
459 wake_up(&server->response_q);
460 continue;
461 }
462 } else if (temp[0] != (char) 0) {
463 cERROR(1,("Unknown RFC 1002 frame"));
464 cifs_dump_mem(" Received Data: ", temp, length);
465 cifs_reconnect(server);
466 csocket = server->ssocket;
467 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700468 }
469
470 /* else we have an SMB response */
471 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700472 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700473 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700474 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700475 cifs_reconnect(server);
476 csocket = server->ssocket;
477 wake_up(&server->response_q);
478 continue;
479 }
480
481 /* else length ok */
482 reconnect = 0;
483
484 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
485 isLargeBuf = TRUE;
486 memcpy(bigbuf, smallbuf, 4);
487 smb_buffer = bigbuf;
488 }
489 length = 0;
490 iov.iov_base = 4 + (char *)smb_buffer;
491 iov.iov_len = pdu_length;
492 for (total_read = 0; total_read < pdu_length;
493 total_read += length) {
494 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
495 pdu_length - total_read, 0);
496 if((server->tcpStatus == CifsExiting) ||
497 (length == -EINTR)) {
498 /* then will exit */
499 reconnect = 2;
500 break;
501 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700502 cifs_reconnect(server);
503 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700504 /* Reconnect wakes up rspns q */
505 /* Now we will reread sock */
506 reconnect = 1;
507 break;
508 } else if ((length == -ERESTARTSYS) ||
509 (length == -EAGAIN)) {
510 msleep(1); /* minimum sleep to prevent looping,
511 allowing socket to clear and app
512 threads to set tcpStatus
513 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700514 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700515 } else if (length <= 0) {
516 cERROR(1,("Received no data, expecting %d",
517 pdu_length - total_read));
518 cifs_reconnect(server);
519 csocket = server->ssocket;
520 reconnect = 1;
521 break;
Steve French46810cb2005-04-28 22:41:09 -0700522 }
523 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700524 if(reconnect == 2)
525 break;
526 else if(reconnect == 1)
527 continue;
528
529 length += 4; /* account for rfc1002 hdr */
530
531
532 dump_smb(smb_buffer, length);
533 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
534 cERROR(1, ("Bad SMB Received "));
535 continue;
536 }
537
538
539 task_to_wake = NULL;
540 spin_lock(&GlobalMid_Lock);
541 list_for_each(tmp, &server->pending_mid_q) {
542 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
543
544 if ((mid_entry->mid == smb_buffer->Mid) &&
545 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
546 (mid_entry->command == smb_buffer->Command)) {
547 cFYI(1,("Found Mid 0x%x wake", mid_entry->mid));
548
549 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
550 /* We have a multipart transact2 resp */
551 if(mid_entry->resp_buf) {
552 /* merge response - fix up 1st*/
553 if(coalesce_t2(smb_buffer,
554 mid_entry->resp_buf)) {
555 isMultiRsp = TRUE;
556 break;
557 } else {
558 /* all parts received */
559 goto multi_t2_fnd;
560 }
561 } else {
562 if(!isLargeBuf) {
563 cERROR(1,("1st trans2 resp needs bigbuf"));
564 /* BB maybe we can fix this up, switch
565 to already allocated large buffer? */
566 } else {
567 mid_entry->resp_buf =
568 smb_buffer;
569 mid_entry->largeBuf = 1;
570 isMultiRsp = TRUE;
571 bigbuf = NULL;
572 }
573 }
574 break;
575 }
576 mid_entry->resp_buf = smb_buffer;
577 if(isLargeBuf)
578 mid_entry->largeBuf = 1;
579 else
580 mid_entry->largeBuf = 0;
581multi_t2_fnd:
582 task_to_wake = mid_entry->tsk;
583 mid_entry->midState = MID_RESPONSE_RECEIVED;
584 break;
585 }
586 }
587 spin_unlock(&GlobalMid_Lock);
588 if (task_to_wake) {
589 if(isLargeBuf)
590 bigbuf = NULL;
591 else
592 smallbuf = NULL;
593 /* smb buffer freed by user thread when done */
594 wake_up_process(task_to_wake);
595 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
596 && (isMultiRsp == FALSE)) {
597 cERROR(1, ("No task to wake, unknown frame rcvd!"));
598 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
599 }
600 } /* end while !EXITING */
601
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 spin_lock(&GlobalMid_Lock);
603 server->tcpStatus = CifsExiting;
604 server->tsk = NULL;
605 atomic_set(&server->inFlight, 0);
606 spin_unlock(&GlobalMid_Lock);
607 /* Although there should not be any requests blocked on
608 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700609 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 to the same server - they now will see the session is in exit state
611 and get out of SendReceive. */
612 wake_up_all(&server->request_q);
613 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700614 msleep(125);
615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if(server->ssocket) {
617 sock_release(csocket);
618 server->ssocket = NULL;
619 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700620 /* buffer usuallly freed in free_mid - need to free it here on exit */
621 if (bigbuf != NULL)
622 cifs_buf_release(bigbuf);
623 if (smallbuf != NULL)
624 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 read_lock(&GlobalSMBSeslock);
627 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700628 /* loop through server session structures attached to this and
629 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 list_for_each(tmp, &GlobalSMBSessionList) {
631 ses =
632 list_entry(tmp, struct cifsSesInfo,
633 cifsSessionList);
634 if (ses->server == server) {
635 ses->status = CifsExiting;
636 ses->server = NULL;
637 }
638 }
639 read_unlock(&GlobalSMBSeslock);
640 } else {
641 spin_lock(&GlobalMid_Lock);
642 list_for_each(tmp, &server->pending_mid_q) {
643 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
644 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
645 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700646 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 task_to_wake = mid_entry->tsk;
648 if(task_to_wake) {
649 wake_up_process(task_to_wake);
650 }
651 }
652 }
653 spin_unlock(&GlobalMid_Lock);
654 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700656 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 }
658
659 if (list_empty(&server->pending_mid_q)) {
660 /* mpx threads have not exited yet give them
661 at least the smb send timeout time for long ops */
662 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700663 msleep(46);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 /* if threads still have not exited they are probably never
665 coming home not much else we can do but free the memory */
666 }
667 kfree(server);
668
669 write_lock(&GlobalSMBSeslock);
670 atomic_dec(&tcpSesAllocCount);
671 length = tcpSesAllocCount.counter;
672 write_unlock(&GlobalSMBSeslock);
673 if(length > 0) {
674 mempool_resize(cifs_req_poolp,
675 length + cifs_min_rcv,
676 GFP_KERNEL);
677 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700678
679 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 return 0;
681}
682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683static int
684cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
685{
686 char *value;
687 char *data;
688 unsigned int temp_len, i, j;
689 char separator[2];
690
691 separator[0] = ',';
692 separator[1] = 0;
693
694 memset(vol->source_rfc1001_name,0x20,15);
695 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
696 /* does not have to be a perfect mapping since the field is
697 informational, only used for servers that do not support
698 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700699 vol->source_rfc1001_name[i] =
700 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 }
702 vol->source_rfc1001_name[15] = 0;
703
704 vol->linux_uid = current->uid; /* current->euid instead? */
705 vol->linux_gid = current->gid;
706 vol->dir_mode = S_IRWXUGO;
707 /* 2767 perms indicate mandatory locking support */
708 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
709
710 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
711 vol->rw = TRUE;
712
713 if (!options)
714 return 1;
715
716 if(strncmp(options,"sep=",4) == 0) {
717 if(options[4] != 0) {
718 separator[0] = options[4];
719 options += 5;
720 } else {
721 cFYI(1,("Null separator not allowed"));
722 }
723 }
724
725 while ((data = strsep(&options, separator)) != NULL) {
726 if (!*data)
727 continue;
728 if ((value = strchr(data, '=')) != NULL)
729 *value++ = '\0';
730
731 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
732 vol->no_xattr = 0;
733 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
734 vol->no_xattr = 1;
735 } else if (strnicmp(data, "user", 4) == 0) {
736 if (!value || !*value) {
737 printk(KERN_WARNING
738 "CIFS: invalid or missing username\n");
739 return 1; /* needs_arg; */
740 }
741 if (strnlen(value, 200) < 200) {
742 vol->username = value;
743 } else {
744 printk(KERN_WARNING "CIFS: username too long\n");
745 return 1;
746 }
747 } else if (strnicmp(data, "pass", 4) == 0) {
748 if (!value) {
749 vol->password = NULL;
750 continue;
751 } else if(value[0] == 0) {
752 /* check if string begins with double comma
753 since that would mean the password really
754 does start with a comma, and would not
755 indicate an empty string */
756 if(value[1] != separator[0]) {
757 vol->password = NULL;
758 continue;
759 }
760 }
761 temp_len = strlen(value);
762 /* removed password length check, NTLM passwords
763 can be arbitrarily long */
764
765 /* if comma in password, the string will be
766 prematurely null terminated. Commas in password are
767 specified across the cifs mount interface by a double
768 comma ie ,, and a comma used as in other cases ie ','
769 as a parameter delimiter/separator is single and due
770 to the strsep above is temporarily zeroed. */
771
772 /* NB: password legally can have multiple commas and
773 the only illegal character in a password is null */
774
Steve French09d1db52005-04-28 22:41:08 -0700775 if ((value[temp_len] == 0) &&
776 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 /* reinsert comma */
778 value[temp_len] = separator[0];
779 temp_len+=2; /* move after the second comma */
780 while(value[temp_len] != 0) {
781 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700782 if (value[temp_len+1] ==
783 separator[0]) {
784 /* skip second comma */
785 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 } else {
787 /* single comma indicating start
788 of next parm */
789 break;
790 }
791 }
792 temp_len++;
793 }
794 if(value[temp_len] == 0) {
795 options = NULL;
796 } else {
797 value[temp_len] = 0;
798 /* point option to start of next parm */
799 options = value + temp_len + 1;
800 }
801 /* go from value to value + temp_len condensing
802 double commas to singles. Note that this ends up
803 allocating a few bytes too many, which is ok */
Steve French433dc242005-04-28 22:41:08 -0700804 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
805 if(vol->password == NULL) {
806 printk("CIFS: no memory for pass\n");
807 return 1;
808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 for(i=0,j=0;i<temp_len;i++,j++) {
810 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700811 if(value[i] == separator[0]
812 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 /* skip second comma */
814 i++;
815 }
816 }
817 vol->password[j] = 0;
818 } else {
Steve French09d1db52005-04-28 22:41:08 -0700819 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700820 if(vol->password == NULL) {
821 printk("CIFS: no memory for pass\n");
822 return 1;
823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 strcpy(vol->password, value);
825 }
826 } else if (strnicmp(data, "ip", 2) == 0) {
827 if (!value || !*value) {
828 vol->UNCip = NULL;
829 } else if (strnlen(value, 35) < 35) {
830 vol->UNCip = value;
831 } else {
832 printk(KERN_WARNING "CIFS: ip address too long\n");
833 return 1;
834 }
835 } else if ((strnicmp(data, "unc", 3) == 0)
836 || (strnicmp(data, "target", 6) == 0)
837 || (strnicmp(data, "path", 4) == 0)) {
838 if (!value || !*value) {
839 printk(KERN_WARNING
840 "CIFS: invalid path to network resource\n");
841 return 1; /* needs_arg; */
842 }
843 if ((temp_len = strnlen(value, 300)) < 300) {
844 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
845 if(vol->UNC == NULL)
846 return 1;
847 strcpy(vol->UNC,value);
848 if (strncmp(vol->UNC, "//", 2) == 0) {
849 vol->UNC[0] = '\\';
850 vol->UNC[1] = '\\';
851 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
852 printk(KERN_WARNING
853 "CIFS: UNC Path does not begin with // or \\\\ \n");
854 return 1;
855 }
856 } else {
857 printk(KERN_WARNING "CIFS: UNC name too long\n");
858 return 1;
859 }
860 } else if ((strnicmp(data, "domain", 3) == 0)
861 || (strnicmp(data, "workgroup", 5) == 0)) {
862 if (!value || !*value) {
863 printk(KERN_WARNING "CIFS: invalid domain name\n");
864 return 1; /* needs_arg; */
865 }
866 /* BB are there cases in which a comma can be valid in
867 a domain name and need special handling? */
868 if (strnlen(value, 65) < 65) {
869 vol->domainname = value;
870 cFYI(1, ("Domain name set"));
871 } else {
872 printk(KERN_WARNING "CIFS: domain name too long\n");
873 return 1;
874 }
875 } else if (strnicmp(data, "iocharset", 9) == 0) {
876 if (!value || !*value) {
877 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
878 return 1; /* needs_arg; */
879 }
880 if (strnlen(value, 65) < 65) {
881 if(strnicmp(value,"default",7))
882 vol->iocharset = value;
883 /* if iocharset not set load_nls_default used by caller */
884 cFYI(1, ("iocharset set to %s",value));
885 } else {
886 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
887 return 1;
888 }
889 } else if (strnicmp(data, "uid", 3) == 0) {
890 if (value && *value) {
891 vol->linux_uid =
892 simple_strtoul(value, &value, 0);
893 }
894 } else if (strnicmp(data, "gid", 3) == 0) {
895 if (value && *value) {
896 vol->linux_gid =
897 simple_strtoul(value, &value, 0);
898 }
899 } else if (strnicmp(data, "file_mode", 4) == 0) {
900 if (value && *value) {
901 vol->file_mode =
902 simple_strtoul(value, &value, 0);
903 }
904 } else if (strnicmp(data, "dir_mode", 4) == 0) {
905 if (value && *value) {
906 vol->dir_mode =
907 simple_strtoul(value, &value, 0);
908 }
909 } else if (strnicmp(data, "dirmode", 4) == 0) {
910 if (value && *value) {
911 vol->dir_mode =
912 simple_strtoul(value, &value, 0);
913 }
914 } else if (strnicmp(data, "port", 4) == 0) {
915 if (value && *value) {
916 vol->port =
917 simple_strtoul(value, &value, 0);
918 }
919 } else if (strnicmp(data, "rsize", 5) == 0) {
920 if (value && *value) {
921 vol->rsize =
922 simple_strtoul(value, &value, 0);
923 }
924 } else if (strnicmp(data, "wsize", 5) == 0) {
925 if (value && *value) {
926 vol->wsize =
927 simple_strtoul(value, &value, 0);
928 }
929 } else if (strnicmp(data, "sockopt", 5) == 0) {
930 if (value && *value) {
931 vol->sockopt =
932 simple_strtoul(value, &value, 0);
933 }
934 } else if (strnicmp(data, "netbiosname", 4) == 0) {
935 if (!value || !*value || (*value == ' ')) {
936 cFYI(1,("invalid (empty) netbiosname specified"));
937 } else {
938 memset(vol->source_rfc1001_name,0x20,15);
939 for(i=0;i<15;i++) {
940 /* BB are there cases in which a comma can be
941 valid in this workstation netbios name (and need
942 special handling)? */
943
944 /* We do not uppercase netbiosname for user */
945 if (value[i]==0)
946 break;
947 else
948 vol->source_rfc1001_name[i] = value[i];
949 }
950 /* The string has 16th byte zero still from
951 set at top of the function */
952 if((i==15) && (value[i] != 0))
953 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
954 }
955 } else if (strnicmp(data, "credentials", 4) == 0) {
956 /* ignore */
957 } else if (strnicmp(data, "version", 3) == 0) {
958 /* ignore */
959 } else if (strnicmp(data, "guest",5) == 0) {
960 /* ignore */
961 } else if (strnicmp(data, "rw", 2) == 0) {
962 vol->rw = TRUE;
963 } else if ((strnicmp(data, "suid", 4) == 0) ||
964 (strnicmp(data, "nosuid", 6) == 0) ||
965 (strnicmp(data, "exec", 4) == 0) ||
966 (strnicmp(data, "noexec", 6) == 0) ||
967 (strnicmp(data, "nodev", 5) == 0) ||
968 (strnicmp(data, "noauto", 6) == 0) ||
969 (strnicmp(data, "dev", 3) == 0)) {
970 /* The mount tool or mount.cifs helper (if present)
971 uses these opts to set flags, and the flags are read
972 by the kernel vfs layer before we get here (ie
973 before read super) so there is no point trying to
974 parse these options again and set anything and it
975 is ok to just ignore them */
976 continue;
977 } else if (strnicmp(data, "ro", 2) == 0) {
978 vol->rw = FALSE;
979 } else if (strnicmp(data, "hard", 4) == 0) {
980 vol->retry = 1;
981 } else if (strnicmp(data, "soft", 4) == 0) {
982 vol->retry = 0;
983 } else if (strnicmp(data, "perm", 4) == 0) {
984 vol->noperm = 0;
985 } else if (strnicmp(data, "noperm", 6) == 0) {
986 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -0700987 } else if (strnicmp(data, "mapchars", 8) == 0) {
988 vol->remap = 1;
989 } else if (strnicmp(data, "nomapchars", 10) == 0) {
990 vol->remap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 } else if (strnicmp(data, "setuids", 7) == 0) {
992 vol->setuids = 1;
993 } else if (strnicmp(data, "nosetuids", 9) == 0) {
994 vol->setuids = 0;
995 } else if (strnicmp(data, "nohard", 6) == 0) {
996 vol->retry = 0;
997 } else if (strnicmp(data, "nosoft", 6) == 0) {
998 vol->retry = 1;
999 } else if (strnicmp(data, "nointr", 6) == 0) {
1000 vol->intr = 0;
1001 } else if (strnicmp(data, "intr", 4) == 0) {
1002 vol->intr = 1;
1003 } else if (strnicmp(data, "serverino",7) == 0) {
1004 vol->server_ino = 1;
1005 } else if (strnicmp(data, "noserverino",9) == 0) {
1006 vol->server_ino = 0;
1007 } else if (strnicmp(data, "acl",3) == 0) {
1008 vol->no_psx_acl = 0;
1009 } else if (strnicmp(data, "noacl",5) == 0) {
1010 vol->no_psx_acl = 1;
1011 } else if (strnicmp(data, "direct",6) == 0) {
1012 vol->direct_io = 1;
1013 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1014 vol->direct_io = 1;
1015 } else if (strnicmp(data, "in6_addr",8) == 0) {
1016 if (!value || !*value) {
1017 vol->in6_addr = NULL;
1018 } else if (strnlen(value, 49) == 48) {
1019 vol->in6_addr = value;
1020 } else {
1021 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1022 return 1;
1023 }
1024 } else if (strnicmp(data, "noac", 4) == 0) {
1025 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1026 } else
1027 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1028 }
1029 if (vol->UNC == NULL) {
1030 if(devname == NULL) {
1031 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1032 return 1;
1033 }
1034 if ((temp_len = strnlen(devname, 300)) < 300) {
1035 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1036 if(vol->UNC == NULL)
1037 return 1;
1038 strcpy(vol->UNC,devname);
1039 if (strncmp(vol->UNC, "//", 2) == 0) {
1040 vol->UNC[0] = '\\';
1041 vol->UNC[1] = '\\';
1042 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1043 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1044 return 1;
1045 }
1046 } else {
1047 printk(KERN_WARNING "CIFS: UNC name too long\n");
1048 return 1;
1049 }
1050 }
1051 if(vol->UNCip == NULL)
1052 vol->UNCip = &vol->UNC[2];
1053
1054 return 0;
1055}
1056
1057static struct cifsSesInfo *
1058cifs_find_tcp_session(struct in_addr * target_ip_addr,
1059 struct in6_addr *target_ip6_addr,
1060 char *userName, struct TCP_Server_Info **psrvTcp)
1061{
1062 struct list_head *tmp;
1063 struct cifsSesInfo *ses;
1064 *psrvTcp = NULL;
1065 read_lock(&GlobalSMBSeslock);
1066
1067 list_for_each(tmp, &GlobalSMBSessionList) {
1068 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1069 if (ses->server) {
1070 if((target_ip_addr &&
1071 (ses->server->addr.sockAddr.sin_addr.s_addr
1072 == target_ip_addr->s_addr)) || (target_ip6_addr
1073 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1074 target_ip6_addr,sizeof(*target_ip6_addr)))){
1075 /* BB lock server and tcp session and increment use count here?? */
1076 *psrvTcp = ses->server; /* found a match on the TCP session */
1077 /* BB check if reconnection needed */
1078 if (strncmp
1079 (ses->userName, userName,
1080 MAX_USERNAME_SIZE) == 0){
1081 read_unlock(&GlobalSMBSeslock);
1082 return ses; /* found exact match on both tcp and SMB sessions */
1083 }
1084 }
1085 }
1086 /* else tcp and smb sessions need reconnection */
1087 }
1088 read_unlock(&GlobalSMBSeslock);
1089 return NULL;
1090}
1091
1092static struct cifsTconInfo *
1093find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1094{
1095 struct list_head *tmp;
1096 struct cifsTconInfo *tcon;
1097
1098 read_lock(&GlobalSMBSeslock);
1099 list_for_each(tmp, &GlobalTreeConnectionList) {
1100 cFYI(1, ("Next tcon - "));
1101 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1102 if (tcon->ses) {
1103 if (tcon->ses->server) {
1104 cFYI(1,
1105 (" old ip addr: %x == new ip %x ?",
1106 tcon->ses->server->addr.sockAddr.sin_addr.
1107 s_addr, new_target_ip_addr));
1108 if (tcon->ses->server->addr.sockAddr.sin_addr.
1109 s_addr == new_target_ip_addr) {
1110 /* BB lock tcon and server and tcp session and increment use count here? */
1111 /* found a match on the TCP session */
1112 /* BB check if reconnection needed */
1113 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1114 tcon->treeName, uncName));
1115 if (strncmp
1116 (tcon->treeName, uncName,
1117 MAX_TREE_SIZE) == 0) {
1118 cFYI(1,
1119 ("Matched UNC, old user: %s == new: %s ?",
1120 tcon->treeName, uncName));
1121 if (strncmp
1122 (tcon->ses->userName,
1123 userName,
1124 MAX_USERNAME_SIZE) == 0) {
1125 read_unlock(&GlobalSMBSeslock);
1126 return tcon;/* also matched user (smb session)*/
1127 }
1128 }
1129 }
1130 }
1131 }
1132 }
1133 read_unlock(&GlobalSMBSeslock);
1134 return NULL;
1135}
1136
1137int
1138connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001139 const char *old_path, const struct nls_table *nls_codepage,
1140 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
1142 unsigned char *referrals = NULL;
1143 unsigned int num_referrals;
1144 int rc = 0;
1145
1146 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001147 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
1149 /* BB Add in code to: if valid refrl, if not ip address contact
1150 the helper that resolves tcp names, mount to it, try to
1151 tcon to it unmount it if fail */
1152
1153 if(referrals)
1154 kfree(referrals);
1155
1156 return rc;
1157}
1158
1159int
1160get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1161 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001162 unsigned int *pnum_referrals,
1163 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164{
1165 char *temp_unc;
1166 int rc = 0;
1167
1168 *pnum_referrals = 0;
1169
1170 if (pSesInfo->ipc_tid == 0) {
1171 temp_unc = kmalloc(2 /* for slashes */ +
1172 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1173 + 1 + 4 /* slash IPC$ */ + 2,
1174 GFP_KERNEL);
1175 if (temp_unc == NULL)
1176 return -ENOMEM;
1177 temp_unc[0] = '\\';
1178 temp_unc[1] = '\\';
1179 strcpy(temp_unc + 2, pSesInfo->serverName);
1180 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1181 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1182 cFYI(1,
1183 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1184 kfree(temp_unc);
1185 }
1186 if (rc == 0)
1187 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001188 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 return rc;
1191}
1192
1193/* See RFC1001 section 14 on representation of Netbios names */
1194static void rfc1002mangle(char * target,char * source, unsigned int length)
1195{
1196 unsigned int i,j;
1197
1198 for(i=0,j=0;i<(length);i++) {
1199 /* mask a nibble at a time and encode */
1200 target[j] = 'A' + (0x0F & (source[i] >> 4));
1201 target[j+1] = 'A' + (0x0F & source[i]);
1202 j+=2;
1203 }
1204
1205}
1206
1207
1208static int
1209ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1210 char * netbios_name)
1211{
1212 int rc = 0;
1213 int connected = 0;
1214 __be16 orig_port = 0;
1215
1216 if(*csocket == NULL) {
1217 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1218 if (rc < 0) {
1219 cERROR(1, ("Error %d creating socket",rc));
1220 *csocket = NULL;
1221 return rc;
1222 } else {
1223 /* BB other socket options to set KEEPALIVE, NODELAY? */
1224 cFYI(1,("Socket created"));
1225 (*csocket)->sk->sk_allocation = GFP_NOFS;
1226 }
1227 }
1228
1229 psin_server->sin_family = AF_INET;
1230 if(psin_server->sin_port) { /* user overrode default port */
1231 rc = (*csocket)->ops->connect(*csocket,
1232 (struct sockaddr *) psin_server,
1233 sizeof (struct sockaddr_in),0);
1234 if (rc >= 0)
1235 connected = 1;
1236 }
1237
1238 if(!connected) {
1239 /* save original port so we can retry user specified port
1240 later if fall back ports fail this time */
1241 orig_port = psin_server->sin_port;
1242
1243 /* do not retry on the same port we just failed on */
1244 if(psin_server->sin_port != htons(CIFS_PORT)) {
1245 psin_server->sin_port = htons(CIFS_PORT);
1246
1247 rc = (*csocket)->ops->connect(*csocket,
1248 (struct sockaddr *) psin_server,
1249 sizeof (struct sockaddr_in),0);
1250 if (rc >= 0)
1251 connected = 1;
1252 }
1253 }
1254 if (!connected) {
1255 psin_server->sin_port = htons(RFC1001_PORT);
1256 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1257 psin_server, sizeof (struct sockaddr_in),0);
1258 if (rc >= 0)
1259 connected = 1;
1260 }
1261
1262 /* give up here - unless we want to retry on different
1263 protocol families some day */
1264 if (!connected) {
1265 if(orig_port)
1266 psin_server->sin_port = orig_port;
1267 cFYI(1,("Error %d connecting to server via ipv4",rc));
1268 sock_release(*csocket);
1269 *csocket = NULL;
1270 return rc;
1271 }
1272 /* Eventually check for other socket options to change from
1273 the default. sock_setsockopt not used because it expects
1274 user space buffer */
1275 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1276
1277 /* send RFC1001 sessinit */
1278
1279 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1280 /* some servers require RFC1001 sessinit before sending
1281 negprot - BB check reconnection in case where second
1282 sessinit is sent but no second negprot */
1283 struct rfc1002_session_packet * ses_init_buf;
1284 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001285 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if(ses_init_buf) {
1287 ses_init_buf->trailer.session_req.called_len = 32;
1288 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1289 DEFAULT_CIFS_CALLED_NAME,16);
1290 ses_init_buf->trailer.session_req.calling_len = 32;
1291 /* calling name ends in null (byte 16) from old smb
1292 convention. */
1293 if(netbios_name && (netbios_name[0] !=0)) {
1294 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1295 netbios_name,16);
1296 } else {
1297 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1298 "LINUX_CIFS_CLNT",16);
1299 }
1300 ses_init_buf->trailer.session_req.scope1 = 0;
1301 ses_init_buf->trailer.session_req.scope2 = 0;
1302 smb_buf = (struct smb_hdr *)ses_init_buf;
1303 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1304 smb_buf->smb_buf_length = 0x81000044;
1305 rc = smb_send(*csocket, smb_buf, 0x44,
1306 (struct sockaddr *)psin_server);
1307 kfree(ses_init_buf);
1308 }
1309 /* else the negprot may still work without this
1310 even though malloc failed */
1311
1312 }
1313
1314 return rc;
1315}
1316
1317static int
1318ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1319{
1320 int rc = 0;
1321 int connected = 0;
1322 __be16 orig_port = 0;
1323
1324 if(*csocket == NULL) {
1325 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1326 if (rc < 0) {
1327 cERROR(1, ("Error %d creating ipv6 socket",rc));
1328 *csocket = NULL;
1329 return rc;
1330 } else {
1331 /* BB other socket options to set KEEPALIVE, NODELAY? */
1332 cFYI(1,("ipv6 Socket created"));
1333 (*csocket)->sk->sk_allocation = GFP_NOFS;
1334 }
1335 }
1336
1337 psin_server->sin6_family = AF_INET6;
1338
1339 if(psin_server->sin6_port) { /* user overrode default port */
1340 rc = (*csocket)->ops->connect(*csocket,
1341 (struct sockaddr *) psin_server,
1342 sizeof (struct sockaddr_in6),0);
1343 if (rc >= 0)
1344 connected = 1;
1345 }
1346
1347 if(!connected) {
1348 /* save original port so we can retry user specified port
1349 later if fall back ports fail this time */
1350
1351 orig_port = psin_server->sin6_port;
1352 /* do not retry on the same port we just failed on */
1353 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1354 psin_server->sin6_port = htons(CIFS_PORT);
1355
1356 rc = (*csocket)->ops->connect(*csocket,
1357 (struct sockaddr *) psin_server,
1358 sizeof (struct sockaddr_in6),0);
1359 if (rc >= 0)
1360 connected = 1;
1361 }
1362 }
1363 if (!connected) {
1364 psin_server->sin6_port = htons(RFC1001_PORT);
1365 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1366 psin_server, sizeof (struct sockaddr_in6),0);
1367 if (rc >= 0)
1368 connected = 1;
1369 }
1370
1371 /* give up here - unless we want to retry on different
1372 protocol families some day */
1373 if (!connected) {
1374 if(orig_port)
1375 psin_server->sin6_port = orig_port;
1376 cFYI(1,("Error %d connecting to server via ipv6",rc));
1377 sock_release(*csocket);
1378 *csocket = NULL;
1379 return rc;
1380 }
1381 /* Eventually check for other socket options to change from
1382 the default. sock_setsockopt not used because it expects
1383 user space buffer */
1384 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1385
1386 return rc;
1387}
1388
1389int
1390cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1391 char *mount_data, const char *devname)
1392{
1393 int rc = 0;
1394 int xid;
1395 int address_type = AF_INET;
1396 struct socket *csocket = NULL;
1397 struct sockaddr_in sin_server;
1398 struct sockaddr_in6 sin_server6;
1399 struct smb_vol volume_info;
1400 struct cifsSesInfo *pSesInfo = NULL;
1401 struct cifsSesInfo *existingCifsSes = NULL;
1402 struct cifsTconInfo *tcon = NULL;
1403 struct TCP_Server_Info *srvTcp = NULL;
1404
1405 xid = GetXid();
1406
1407/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1408
1409 memset(&volume_info,0,sizeof(struct smb_vol));
1410 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1411 if(volume_info.UNC)
1412 kfree(volume_info.UNC);
1413 if(volume_info.password)
1414 kfree(volume_info.password);
1415 FreeXid(xid);
1416 return -EINVAL;
1417 }
1418
1419 if (volume_info.username) {
1420 /* BB fixme parse for domain name here */
1421 cFYI(1, ("Username: %s ", volume_info.username));
1422
1423 } else {
1424 cifserror("No username specified ");
1425 /* In userspace mount helper we can get user name from alternate
1426 locations such as env variables and files on disk */
1427 if(volume_info.UNC)
1428 kfree(volume_info.UNC);
1429 if(volume_info.password)
1430 kfree(volume_info.password);
1431 FreeXid(xid);
1432 return -EINVAL;
1433 }
1434
1435 if (volume_info.UNCip && volume_info.UNC) {
1436 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1437
1438 if(rc <= 0) {
1439 /* not ipv4 address, try ipv6 */
1440 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1441 if(rc > 0)
1442 address_type = AF_INET6;
1443 } else {
1444 address_type = AF_INET;
1445 }
1446
1447 if(rc <= 0) {
1448 /* we failed translating address */
1449 if(volume_info.UNC)
1450 kfree(volume_info.UNC);
1451 if(volume_info.password)
1452 kfree(volume_info.password);
1453 FreeXid(xid);
1454 return -EINVAL;
1455 }
1456
1457 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1458 /* success */
1459 rc = 0;
1460 } else if (volume_info.UNCip){
1461 /* BB using ip addr as server name connect to the DFS root below */
1462 cERROR(1,("Connecting to DFS root not implemented yet"));
1463 if(volume_info.UNC)
1464 kfree(volume_info.UNC);
1465 if(volume_info.password)
1466 kfree(volume_info.password);
1467 FreeXid(xid);
1468 return -EINVAL;
1469 } else /* which servers DFS root would we conect to */ {
1470 cERROR(1,
1471 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1472 if(volume_info.UNC)
1473 kfree(volume_info.UNC);
1474 if(volume_info.password)
1475 kfree(volume_info.password);
1476 FreeXid(xid);
1477 return -EINVAL;
1478 }
1479
1480 /* this is needed for ASCII cp to Unicode converts */
1481 if(volume_info.iocharset == NULL) {
1482 cifs_sb->local_nls = load_nls_default();
1483 /* load_nls_default can not return null */
1484 } else {
1485 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1486 if(cifs_sb->local_nls == NULL) {
1487 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1488 if(volume_info.UNC)
1489 kfree(volume_info.UNC);
1490 if(volume_info.password)
1491 kfree(volume_info.password);
1492 FreeXid(xid);
1493 return -ELIBACC;
1494 }
1495 }
1496
1497 if(address_type == AF_INET)
1498 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1499 NULL /* no ipv6 addr */,
1500 volume_info.username, &srvTcp);
1501 else if(address_type == AF_INET6)
1502 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1503 &sin_server6.sin6_addr,
1504 volume_info.username, &srvTcp);
1505 else {
1506 if(volume_info.UNC)
1507 kfree(volume_info.UNC);
1508 if(volume_info.password)
1509 kfree(volume_info.password);
1510 FreeXid(xid);
1511 return -EINVAL;
1512 }
1513
1514
1515 if (srvTcp) {
1516 cFYI(1, ("Existing tcp session with server found "));
1517 } else { /* create socket */
1518 if(volume_info.port)
1519 sin_server.sin_port = htons(volume_info.port);
1520 else
1521 sin_server.sin_port = 0;
1522 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1523 if (rc < 0) {
1524 cERROR(1,
1525 ("Error connecting to IPv4 socket. Aborting operation"));
1526 if(csocket != NULL)
1527 sock_release(csocket);
1528 if(volume_info.UNC)
1529 kfree(volume_info.UNC);
1530 if(volume_info.password)
1531 kfree(volume_info.password);
1532 FreeXid(xid);
1533 return rc;
1534 }
1535
1536 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1537 if (srvTcp == NULL) {
1538 rc = -ENOMEM;
1539 sock_release(csocket);
1540 if(volume_info.UNC)
1541 kfree(volume_info.UNC);
1542 if(volume_info.password)
1543 kfree(volume_info.password);
1544 FreeXid(xid);
1545 return rc;
1546 } else {
1547 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1548 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1549 atomic_set(&srvTcp->inFlight,0);
1550 /* BB Add code for ipv6 case too */
1551 srvTcp->ssocket = csocket;
1552 srvTcp->protocolType = IPV4;
1553 init_waitqueue_head(&srvTcp->response_q);
1554 init_waitqueue_head(&srvTcp->request_q);
1555 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1556 /* at this point we are the only ones with the pointer
1557 to the struct since the kernel thread not created yet
1558 so no need to spinlock this init of tcpStatus */
1559 srvTcp->tcpStatus = CifsNew;
1560 init_MUTEX(&srvTcp->tcpSem);
1561 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1562 CLONE_FS | CLONE_FILES | CLONE_VM);
1563 if(rc < 0) {
1564 rc = -ENOMEM;
1565 sock_release(csocket);
1566 if(volume_info.UNC)
1567 kfree(volume_info.UNC);
1568 if(volume_info.password)
1569 kfree(volume_info.password);
1570 FreeXid(xid);
1571 return rc;
1572 } else
1573 rc = 0;
1574 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001575 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 }
1577 }
1578
1579 if (existingCifsSes) {
1580 pSesInfo = existingCifsSes;
1581 cFYI(1, ("Existing smb sess found "));
1582 if(volume_info.password)
1583 kfree(volume_info.password);
1584 /* volume_info.UNC freed at end of function */
1585 } else if (!rc) {
1586 cFYI(1, ("Existing smb sess not found "));
1587 pSesInfo = sesInfoAlloc();
1588 if (pSesInfo == NULL)
1589 rc = -ENOMEM;
1590 else {
1591 pSesInfo->server = srvTcp;
1592 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1593 NIPQUAD(sin_server.sin_addr.s_addr));
1594 }
1595
1596 if (!rc){
1597 /* volume_info.password freed at unmount */
1598 if (volume_info.password)
1599 pSesInfo->password = volume_info.password;
1600 if (volume_info.username)
1601 strncpy(pSesInfo->userName,
1602 volume_info.username,MAX_USERNAME_SIZE);
1603 if (volume_info.domainname)
1604 strncpy(pSesInfo->domainName,
1605 volume_info.domainname,MAX_USERNAME_SIZE);
1606 pSesInfo->linux_uid = volume_info.linux_uid;
1607 down(&pSesInfo->sesSem);
1608 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1609 up(&pSesInfo->sesSem);
1610 if(!rc)
1611 atomic_inc(&srvTcp->socketUseCount);
1612 } else
1613 if(volume_info.password)
1614 kfree(volume_info.password);
1615 }
1616
1617 /* search for existing tcon to this server share */
1618 if (!rc) {
1619 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1620 cifs_sb->rsize = volume_info.rsize;
1621 else
1622 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1623 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1624 cifs_sb->wsize = volume_info.wsize;
1625 else
1626 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1627 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1628 cifs_sb->rsize = PAGE_CACHE_SIZE;
1629 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1630 }
1631 cifs_sb->mnt_uid = volume_info.linux_uid;
1632 cifs_sb->mnt_gid = volume_info.linux_gid;
1633 cifs_sb->mnt_file_mode = volume_info.file_mode;
1634 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1635 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1636
1637 if(volume_info.noperm)
1638 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1639 if(volume_info.setuids)
1640 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1641 if(volume_info.server_ino)
1642 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001643 if(volume_info.remap)
1644 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 if(volume_info.no_xattr)
1646 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1647 if(volume_info.direct_io) {
1648 cERROR(1,("mounting share using direct i/o"));
1649 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1650 }
1651
1652 tcon =
1653 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1654 volume_info.username);
1655 if (tcon) {
1656 cFYI(1, ("Found match on UNC path "));
1657 /* we can have only one retry value for a connection
1658 to a share so for resources mounted more than once
1659 to the same server share the last value passed in
1660 for the retry flag is used */
1661 tcon->retry = volume_info.retry;
1662 } else {
1663 tcon = tconInfoAlloc();
1664 if (tcon == NULL)
1665 rc = -ENOMEM;
1666 else {
1667 /* check for null share name ie connect to dfs root */
1668
1669 /* BB check if this works for exactly length three strings */
1670 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1671 && (strchr(volume_info.UNC + 3, '/') ==
1672 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001673 rc = connect_to_dfs_path(xid, pSesInfo,
1674 "", cifs_sb->local_nls,
1675 cifs_sb->mnt_cifs_flags &
1676 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 if(volume_info.UNC)
1678 kfree(volume_info.UNC);
1679 FreeXid(xid);
1680 return -ENODEV;
1681 } else {
1682 rc = CIFSTCon(xid, pSesInfo,
1683 volume_info.UNC,
1684 tcon, cifs_sb->local_nls);
1685 cFYI(1, ("CIFS Tcon rc = %d", rc));
1686 }
1687 if (!rc) {
1688 atomic_inc(&pSesInfo->inUse);
1689 tcon->retry = volume_info.retry;
1690 }
1691 }
1692 }
1693 }
1694 if(pSesInfo) {
1695 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1696 sb->s_maxbytes = (u64) 1 << 63;
1697 } else
1698 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1699 }
1700
1701 sb->s_time_gran = 100;
1702
1703/* on error free sesinfo and tcon struct if needed */
1704 if (rc) {
1705 /* if session setup failed, use count is zero but
1706 we still need to free cifsd thread */
1707 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1708 spin_lock(&GlobalMid_Lock);
1709 srvTcp->tcpStatus = CifsExiting;
1710 spin_unlock(&GlobalMid_Lock);
1711 if(srvTcp->tsk)
1712 send_sig(SIGKILL,srvTcp->tsk,1);
1713 }
1714 /* If find_unc succeeded then rc == 0 so we can not end */
1715 if (tcon) /* up accidently freeing someone elses tcon struct */
1716 tconInfoFree(tcon);
1717 if (existingCifsSes == NULL) {
1718 if (pSesInfo) {
1719 if ((pSesInfo->server) &&
1720 (pSesInfo->status == CifsGood)) {
1721 int temp_rc;
1722 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1723 /* if the socketUseCount is now zero */
1724 if((temp_rc == -ESHUTDOWN) &&
1725 (pSesInfo->server->tsk))
1726 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1727 } else
1728 cFYI(1, ("No session or bad tcon"));
1729 sesInfoFree(pSesInfo);
1730 /* pSesInfo = NULL; */
1731 }
1732 }
1733 } else {
1734 atomic_inc(&tcon->useCount);
1735 cifs_sb->tcon = tcon;
1736 tcon->ses = pSesInfo;
1737
1738 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001739 CIFSSMBQFSDeviceInfo(xid, tcon);
1740 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001742 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 if(!volume_info.no_psx_acl) {
1744 if(CIFS_UNIX_POSIX_ACL_CAP &
1745 le64_to_cpu(tcon->fsUnixInfo.Capability))
1746 cFYI(1,("server negotiated posix acl support"));
1747 sb->s_flags |= MS_POSIXACL;
1748 }
1749 }
1750 }
1751 }
1752
1753 /* volume_info.password is freed above when existing session found
1754 (in which case it is not needed anymore) but when new sesion is created
1755 the password ptr is put in the new session structure (in which case the
1756 password will be freed at unmount time) */
1757 if(volume_info.UNC)
1758 kfree(volume_info.UNC);
1759 FreeXid(xid);
1760 return rc;
1761}
1762
1763static int
1764CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1765 char session_key[CIFS_SESSION_KEY_SIZE],
1766 const struct nls_table *nls_codepage)
1767{
1768 struct smb_hdr *smb_buffer;
1769 struct smb_hdr *smb_buffer_response;
1770 SESSION_SETUP_ANDX *pSMB;
1771 SESSION_SETUP_ANDX *pSMBr;
1772 char *bcc_ptr;
1773 char *user;
1774 char *domain;
1775 int rc = 0;
1776 int remaining_words = 0;
1777 int bytes_returned = 0;
1778 int len;
1779 __u32 capabilities;
1780 __u16 count;
1781
1782 cFYI(1, ("In sesssetup "));
1783 if(ses == NULL)
1784 return -EINVAL;
1785 user = ses->userName;
1786 domain = ses->domainName;
1787 smb_buffer = cifs_buf_get();
1788 if (smb_buffer == NULL) {
1789 return -ENOMEM;
1790 }
1791 smb_buffer_response = smb_buffer;
1792 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1793
1794 /* send SMBsessionSetup here */
1795 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1796 NULL /* no tCon exists yet */ , 13 /* wct */ );
1797
1798 pSMB->req_no_secext.AndXCommand = 0xFF;
1799 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1800 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1801
1802 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1803 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1804
1805 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1806 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1807 if (ses->capabilities & CAP_UNICODE) {
1808 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1809 capabilities |= CAP_UNICODE;
1810 }
1811 if (ses->capabilities & CAP_STATUS32) {
1812 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1813 capabilities |= CAP_STATUS32;
1814 }
1815 if (ses->capabilities & CAP_DFS) {
1816 smb_buffer->Flags2 |= SMBFLG2_DFS;
1817 capabilities |= CAP_DFS;
1818 }
1819 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1820
1821 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1822 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1823
1824 pSMB->req_no_secext.CaseSensitivePasswordLength =
1825 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1826 bcc_ptr = pByteArea(smb_buffer);
1827 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1828 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1829 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1830 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1831
1832 if (ses->capabilities & CAP_UNICODE) {
1833 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1834 *bcc_ptr = 0;
1835 bcc_ptr++;
1836 }
1837 if(user == NULL)
1838 bytes_returned = 0; /* skill null user */
1839 else
1840 bytes_returned =
1841 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1842 nls_codepage);
1843 /* convert number of 16 bit words to bytes */
1844 bcc_ptr += 2 * bytes_returned;
1845 bcc_ptr += 2; /* trailing null */
1846 if (domain == NULL)
1847 bytes_returned =
1848 cifs_strtoUCS((wchar_t *) bcc_ptr,
1849 "CIFS_LINUX_DOM", 32, nls_codepage);
1850 else
1851 bytes_returned =
1852 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1853 nls_codepage);
1854 bcc_ptr += 2 * bytes_returned;
1855 bcc_ptr += 2;
1856 bytes_returned =
1857 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1858 32, nls_codepage);
1859 bcc_ptr += 2 * bytes_returned;
1860 bytes_returned =
1861 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1862 32, nls_codepage);
1863 bcc_ptr += 2 * bytes_returned;
1864 bcc_ptr += 2;
1865 bytes_returned =
1866 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1867 64, nls_codepage);
1868 bcc_ptr += 2 * bytes_returned;
1869 bcc_ptr += 2;
1870 } else {
1871 if(user != NULL) {
1872 strncpy(bcc_ptr, user, 200);
1873 bcc_ptr += strnlen(user, 200);
1874 }
1875 *bcc_ptr = 0;
1876 bcc_ptr++;
1877 if (domain == NULL) {
1878 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1879 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1880 } else {
1881 strncpy(bcc_ptr, domain, 64);
1882 bcc_ptr += strnlen(domain, 64);
1883 *bcc_ptr = 0;
1884 bcc_ptr++;
1885 }
1886 strcpy(bcc_ptr, "Linux version ");
1887 bcc_ptr += strlen("Linux version ");
1888 strcpy(bcc_ptr, system_utsname.release);
1889 bcc_ptr += strlen(system_utsname.release) + 1;
1890 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1891 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1892 }
1893 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1894 smb_buffer->smb_buf_length += count;
1895 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1896
1897 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1898 &bytes_returned, 1);
1899 if (rc) {
1900/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1901 } else if ((smb_buffer_response->WordCount == 3)
1902 || (smb_buffer_response->WordCount == 4)) {
1903 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1904 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1905 if (action & GUEST_LOGIN)
1906 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1907 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1908 cFYI(1, ("UID = %d ", ses->Suid));
1909 /* response can have either 3 or 4 word count - Samba sends 3 */
1910 bcc_ptr = pByteArea(smb_buffer_response);
1911 if ((pSMBr->resp.hdr.WordCount == 3)
1912 || ((pSMBr->resp.hdr.WordCount == 4)
1913 && (blob_len < pSMBr->resp.ByteCount))) {
1914 if (pSMBr->resp.hdr.WordCount == 4)
1915 bcc_ptr += blob_len;
1916
1917 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1918 if ((long) (bcc_ptr) % 2) {
1919 remaining_words =
1920 (BCC(smb_buffer_response) - 1) /2;
1921 bcc_ptr++; /* Unicode strings must be word aligned */
1922 } else {
1923 remaining_words =
1924 BCC(smb_buffer_response) / 2;
1925 }
1926 len =
1927 UniStrnlen((wchar_t *) bcc_ptr,
1928 remaining_words - 1);
1929/* We look for obvious messed up bcc or strings in response so we do not go off
1930 the end since (at least) WIN2K and Windows XP have a major bug in not null
1931 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07001932 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
1933 if(ses->serverOS == NULL)
1934 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 cifs_strfromUCS_le(ses->serverOS,
1936 (wchar_t *)bcc_ptr, len,nls_codepage);
1937 bcc_ptr += 2 * (len + 1);
1938 remaining_words -= len + 1;
1939 ses->serverOS[2 * len] = 0;
1940 ses->serverOS[1 + (2 * len)] = 0;
1941 if (remaining_words > 0) {
1942 len = UniStrnlen((wchar_t *)bcc_ptr,
1943 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07001944 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
1945 if(ses->serverNOS == NULL)
1946 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 cifs_strfromUCS_le(ses->serverNOS,
1948 (wchar_t *)bcc_ptr,len,nls_codepage);
1949 bcc_ptr += 2 * (len + 1);
1950 ses->serverNOS[2 * len] = 0;
1951 ses->serverNOS[1 + (2 * len)] = 0;
1952 if(strncmp(ses->serverNOS,
1953 "NT LAN Manager 4",16) == 0) {
1954 cFYI(1,("NT4 server"));
1955 ses->flags |= CIFS_SES_NT4;
1956 }
1957 remaining_words -= len + 1;
1958 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07001959 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1961 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07001962 kcalloc(1, 2*(len+1),GFP_KERNEL);
1963 if(ses->serverDomain == NULL)
1964 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 cifs_strfromUCS_le(ses->serverDomain,
1966 (wchar_t *)bcc_ptr,len,nls_codepage);
1967 bcc_ptr += 2 * (len + 1);
1968 ses->serverDomain[2*len] = 0;
1969 ses->serverDomain[1+(2*len)] = 0;
1970 } /* else no more room so create dummy domain string */
1971 else
Steve French433dc242005-04-28 22:41:08 -07001972 ses->serverDomain =
1973 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07001975 /* if these kcallocs fail not much we
1976 can do, but better to not fail the
1977 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07001979 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07001981 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 }
1983 } else { /* ASCII */
1984 len = strnlen(bcc_ptr, 1024);
1985 if (((long) bcc_ptr + len) - (long)
1986 pByteArea(smb_buffer_response)
1987 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07001988 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
1989 if(ses->serverOS == NULL)
1990 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 strncpy(ses->serverOS,bcc_ptr, len);
1992
1993 bcc_ptr += len;
1994 bcc_ptr[0] = 0; /* null terminate the string */
1995 bcc_ptr++;
1996
1997 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07001998 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
1999 if(ses->serverNOS == NULL)
2000 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 strncpy(ses->serverNOS, bcc_ptr, len);
2002 bcc_ptr += len;
2003 bcc_ptr[0] = 0;
2004 bcc_ptr++;
2005
2006 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002007 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2008 if(ses->serverDomain == NULL)
2009 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 strncpy(ses->serverDomain, bcc_ptr, len);
2011 bcc_ptr += len;
2012 bcc_ptr[0] = 0;
2013 bcc_ptr++;
2014 } else
2015 cFYI(1,
2016 ("Variable field of length %d extends beyond end of smb ",
2017 len));
2018 }
2019 } else {
2020 cERROR(1,
2021 (" Security Blob Length extends beyond end of SMB"));
2022 }
2023 } else {
2024 cERROR(1,
2025 (" Invalid Word count %d: ",
2026 smb_buffer_response->WordCount));
2027 rc = -EIO;
2028 }
Steve French433dc242005-04-28 22:41:08 -07002029sesssetup_nomem: /* do not return an error on nomem for the info strings,
2030 since that could make reconnection harder, and
2031 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 if (smb_buffer)
2033 cifs_buf_release(smb_buffer);
2034
2035 return rc;
2036}
2037
2038static int
2039CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2040 char *SecurityBlob,int SecurityBlobLength,
2041 const struct nls_table *nls_codepage)
2042{
2043 struct smb_hdr *smb_buffer;
2044 struct smb_hdr *smb_buffer_response;
2045 SESSION_SETUP_ANDX *pSMB;
2046 SESSION_SETUP_ANDX *pSMBr;
2047 char *bcc_ptr;
2048 char *user;
2049 char *domain;
2050 int rc = 0;
2051 int remaining_words = 0;
2052 int bytes_returned = 0;
2053 int len;
2054 __u32 capabilities;
2055 __u16 count;
2056
2057 cFYI(1, ("In spnego sesssetup "));
2058 if(ses == NULL)
2059 return -EINVAL;
2060 user = ses->userName;
2061 domain = ses->domainName;
2062
2063 smb_buffer = cifs_buf_get();
2064 if (smb_buffer == NULL) {
2065 return -ENOMEM;
2066 }
2067 smb_buffer_response = smb_buffer;
2068 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2069
2070 /* send SMBsessionSetup here */
2071 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2072 NULL /* no tCon exists yet */ , 12 /* wct */ );
2073 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2074 pSMB->req.AndXCommand = 0xFF;
2075 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2076 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2077
2078 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2079 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2080
2081 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2082 CAP_EXTENDED_SECURITY;
2083 if (ses->capabilities & CAP_UNICODE) {
2084 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2085 capabilities |= CAP_UNICODE;
2086 }
2087 if (ses->capabilities & CAP_STATUS32) {
2088 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2089 capabilities |= CAP_STATUS32;
2090 }
2091 if (ses->capabilities & CAP_DFS) {
2092 smb_buffer->Flags2 |= SMBFLG2_DFS;
2093 capabilities |= CAP_DFS;
2094 }
2095 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2096
2097 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2098 bcc_ptr = pByteArea(smb_buffer);
2099 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2100 bcc_ptr += SecurityBlobLength;
2101
2102 if (ses->capabilities & CAP_UNICODE) {
2103 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2104 *bcc_ptr = 0;
2105 bcc_ptr++;
2106 }
2107 bytes_returned =
2108 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2109 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2110 bcc_ptr += 2; /* trailing null */
2111 if (domain == NULL)
2112 bytes_returned =
2113 cifs_strtoUCS((wchar_t *) bcc_ptr,
2114 "CIFS_LINUX_DOM", 32, nls_codepage);
2115 else
2116 bytes_returned =
2117 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2118 nls_codepage);
2119 bcc_ptr += 2 * bytes_returned;
2120 bcc_ptr += 2;
2121 bytes_returned =
2122 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2123 32, nls_codepage);
2124 bcc_ptr += 2 * bytes_returned;
2125 bytes_returned =
2126 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2127 nls_codepage);
2128 bcc_ptr += 2 * bytes_returned;
2129 bcc_ptr += 2;
2130 bytes_returned =
2131 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2132 64, nls_codepage);
2133 bcc_ptr += 2 * bytes_returned;
2134 bcc_ptr += 2;
2135 } else {
2136 strncpy(bcc_ptr, user, 200);
2137 bcc_ptr += strnlen(user, 200);
2138 *bcc_ptr = 0;
2139 bcc_ptr++;
2140 if (domain == NULL) {
2141 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2142 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2143 } else {
2144 strncpy(bcc_ptr, domain, 64);
2145 bcc_ptr += strnlen(domain, 64);
2146 *bcc_ptr = 0;
2147 bcc_ptr++;
2148 }
2149 strcpy(bcc_ptr, "Linux version ");
2150 bcc_ptr += strlen("Linux version ");
2151 strcpy(bcc_ptr, system_utsname.release);
2152 bcc_ptr += strlen(system_utsname.release) + 1;
2153 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2154 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2155 }
2156 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2157 smb_buffer->smb_buf_length += count;
2158 pSMB->req.ByteCount = cpu_to_le16(count);
2159
2160 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2161 &bytes_returned, 1);
2162 if (rc) {
2163/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2164 } else if ((smb_buffer_response->WordCount == 3)
2165 || (smb_buffer_response->WordCount == 4)) {
2166 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2167 __u16 blob_len =
2168 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2169 if (action & GUEST_LOGIN)
2170 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2171 if (ses) {
2172 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2173 cFYI(1, ("UID = %d ", ses->Suid));
2174 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2175
2176 /* BB Fix below to make endian neutral !! */
2177
2178 if ((pSMBr->resp.hdr.WordCount == 3)
2179 || ((pSMBr->resp.hdr.WordCount == 4)
2180 && (blob_len <
2181 pSMBr->resp.ByteCount))) {
2182 if (pSMBr->resp.hdr.WordCount == 4) {
2183 bcc_ptr +=
2184 blob_len;
2185 cFYI(1,
2186 ("Security Blob Length %d ",
2187 blob_len));
2188 }
2189
2190 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2191 if ((long) (bcc_ptr) % 2) {
2192 remaining_words =
2193 (BCC(smb_buffer_response)
2194 - 1) / 2;
2195 bcc_ptr++; /* Unicode strings must be word aligned */
2196 } else {
2197 remaining_words =
2198 BCC
2199 (smb_buffer_response) / 2;
2200 }
2201 len =
2202 UniStrnlen((wchar_t *) bcc_ptr,
2203 remaining_words - 1);
2204/* We look for obvious messed up bcc or strings in response so we do not go off
2205 the end since (at least) WIN2K and Windows XP have a major bug in not null
2206 terminating last Unicode string in response */
2207 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002208 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 cifs_strfromUCS_le(ses->serverOS,
2210 (wchar_t *)
2211 bcc_ptr, len,
2212 nls_codepage);
2213 bcc_ptr += 2 * (len + 1);
2214 remaining_words -= len + 1;
2215 ses->serverOS[2 * len] = 0;
2216 ses->serverOS[1 + (2 * len)] = 0;
2217 if (remaining_words > 0) {
2218 len = UniStrnlen((wchar_t *)bcc_ptr,
2219 remaining_words
2220 - 1);
2221 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002222 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 GFP_KERNEL);
2224 cifs_strfromUCS_le(ses->serverNOS,
2225 (wchar_t *)bcc_ptr,
2226 len,
2227 nls_codepage);
2228 bcc_ptr += 2 * (len + 1);
2229 ses->serverNOS[2 * len] = 0;
2230 ses->serverNOS[1 + (2 * len)] = 0;
2231 remaining_words -= len + 1;
2232 if (remaining_words > 0) {
2233 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2234 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002235 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 cifs_strfromUCS_le(ses->serverDomain,
2237 (wchar_t *)bcc_ptr,
2238 len,
2239 nls_codepage);
2240 bcc_ptr += 2*(len+1);
2241 ses->serverDomain[2*len] = 0;
2242 ses->serverDomain[1+(2*len)] = 0;
2243 } /* else no more room so create dummy domain string */
2244 else
2245 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002246 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002248 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2249 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 }
2251 } else { /* ASCII */
2252
2253 len = strnlen(bcc_ptr, 1024);
2254 if (((long) bcc_ptr + len) - (long)
2255 pByteArea(smb_buffer_response)
2256 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002257 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 strncpy(ses->serverOS, bcc_ptr, len);
2259
2260 bcc_ptr += len;
2261 bcc_ptr[0] = 0; /* null terminate the string */
2262 bcc_ptr++;
2263
2264 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002265 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 strncpy(ses->serverNOS, bcc_ptr, len);
2267 bcc_ptr += len;
2268 bcc_ptr[0] = 0;
2269 bcc_ptr++;
2270
2271 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002272 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 strncpy(ses->serverDomain, bcc_ptr, len);
2274 bcc_ptr += len;
2275 bcc_ptr[0] = 0;
2276 bcc_ptr++;
2277 } else
2278 cFYI(1,
2279 ("Variable field of length %d extends beyond end of smb ",
2280 len));
2281 }
2282 } else {
2283 cERROR(1,
2284 (" Security Blob Length extends beyond end of SMB"));
2285 }
2286 } else {
2287 cERROR(1, ("No session structure passed in."));
2288 }
2289 } else {
2290 cERROR(1,
2291 (" Invalid Word count %d: ",
2292 smb_buffer_response->WordCount));
2293 rc = -EIO;
2294 }
2295
2296 if (smb_buffer)
2297 cifs_buf_release(smb_buffer);
2298
2299 return rc;
2300}
2301
2302static int
2303CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2304 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2305 const struct nls_table *nls_codepage)
2306{
2307 struct smb_hdr *smb_buffer;
2308 struct smb_hdr *smb_buffer_response;
2309 SESSION_SETUP_ANDX *pSMB;
2310 SESSION_SETUP_ANDX *pSMBr;
2311 char *bcc_ptr;
2312 char *domain;
2313 int rc = 0;
2314 int remaining_words = 0;
2315 int bytes_returned = 0;
2316 int len;
2317 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2318 PNEGOTIATE_MESSAGE SecurityBlob;
2319 PCHALLENGE_MESSAGE SecurityBlob2;
2320 __u32 negotiate_flags, capabilities;
2321 __u16 count;
2322
2323 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2324 if(ses == NULL)
2325 return -EINVAL;
2326 domain = ses->domainName;
2327 *pNTLMv2_flag = FALSE;
2328 smb_buffer = cifs_buf_get();
2329 if (smb_buffer == NULL) {
2330 return -ENOMEM;
2331 }
2332 smb_buffer_response = smb_buffer;
2333 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2334 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2335
2336 /* send SMBsessionSetup here */
2337 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2338 NULL /* no tCon exists yet */ , 12 /* wct */ );
2339 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2340 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2341
2342 pSMB->req.AndXCommand = 0xFF;
2343 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2344 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2345
2346 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2347 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2348
2349 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2350 CAP_EXTENDED_SECURITY;
2351 if (ses->capabilities & CAP_UNICODE) {
2352 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2353 capabilities |= CAP_UNICODE;
2354 }
2355 if (ses->capabilities & CAP_STATUS32) {
2356 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2357 capabilities |= CAP_STATUS32;
2358 }
2359 if (ses->capabilities & CAP_DFS) {
2360 smb_buffer->Flags2 |= SMBFLG2_DFS;
2361 capabilities |= CAP_DFS;
2362 }
2363 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2364
2365 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2366 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2367 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2368 SecurityBlob->MessageType = NtLmNegotiate;
2369 negotiate_flags =
2370 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2371 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2372 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2373 if(sign_CIFS_PDUs)
2374 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2375 if(ntlmv2_support)
2376 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2377 /* setup pointers to domain name and workstation name */
2378 bcc_ptr += SecurityBlobLength;
2379
2380 SecurityBlob->WorkstationName.Buffer = 0;
2381 SecurityBlob->WorkstationName.Length = 0;
2382 SecurityBlob->WorkstationName.MaximumLength = 0;
2383
2384 if (domain == NULL) {
2385 SecurityBlob->DomainName.Buffer = 0;
2386 SecurityBlob->DomainName.Length = 0;
2387 SecurityBlob->DomainName.MaximumLength = 0;
2388 } else {
2389 __u16 len;
2390 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2391 strncpy(bcc_ptr, domain, 63);
2392 len = strnlen(domain, 64);
2393 SecurityBlob->DomainName.MaximumLength =
2394 cpu_to_le16(len);
2395 SecurityBlob->DomainName.Buffer =
2396 cpu_to_le32((long) &SecurityBlob->
2397 DomainString -
2398 (long) &SecurityBlob->Signature);
2399 bcc_ptr += len;
2400 SecurityBlobLength += len;
2401 SecurityBlob->DomainName.Length =
2402 cpu_to_le16(len);
2403 }
2404 if (ses->capabilities & CAP_UNICODE) {
2405 if ((long) bcc_ptr % 2) {
2406 *bcc_ptr = 0;
2407 bcc_ptr++;
2408 }
2409
2410 bytes_returned =
2411 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2412 32, nls_codepage);
2413 bcc_ptr += 2 * bytes_returned;
2414 bytes_returned =
2415 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2416 nls_codepage);
2417 bcc_ptr += 2 * bytes_returned;
2418 bcc_ptr += 2; /* null terminate Linux version */
2419 bytes_returned =
2420 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2421 64, nls_codepage);
2422 bcc_ptr += 2 * bytes_returned;
2423 *(bcc_ptr + 1) = 0;
2424 *(bcc_ptr + 2) = 0;
2425 bcc_ptr += 2; /* null terminate network opsys string */
2426 *(bcc_ptr + 1) = 0;
2427 *(bcc_ptr + 2) = 0;
2428 bcc_ptr += 2; /* null domain */
2429 } else { /* ASCII */
2430 strcpy(bcc_ptr, "Linux version ");
2431 bcc_ptr += strlen("Linux version ");
2432 strcpy(bcc_ptr, system_utsname.release);
2433 bcc_ptr += strlen(system_utsname.release) + 1;
2434 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2435 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2436 bcc_ptr++; /* empty domain field */
2437 *bcc_ptr = 0;
2438 }
2439 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2440 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2441 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2442 smb_buffer->smb_buf_length += count;
2443 pSMB->req.ByteCount = cpu_to_le16(count);
2444
2445 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2446 &bytes_returned, 1);
2447
2448 if (smb_buffer_response->Status.CifsError ==
2449 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2450 rc = 0;
2451
2452 if (rc) {
2453/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2454 } else if ((smb_buffer_response->WordCount == 3)
2455 || (smb_buffer_response->WordCount == 4)) {
2456 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2457 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2458
2459 if (action & GUEST_LOGIN)
2460 cFYI(1, (" Guest login"));
2461 /* Do we want to set anything in SesInfo struct when guest login? */
2462
2463 bcc_ptr = pByteArea(smb_buffer_response);
2464 /* response can have either 3 or 4 word count - Samba sends 3 */
2465
2466 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2467 if (SecurityBlob2->MessageType != NtLmChallenge) {
2468 cFYI(1,
2469 ("Unexpected NTLMSSP message type received %d",
2470 SecurityBlob2->MessageType));
2471 } else if (ses) {
2472 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2473 cFYI(1, ("UID = %d ", ses->Suid));
2474 if ((pSMBr->resp.hdr.WordCount == 3)
2475 || ((pSMBr->resp.hdr.WordCount == 4)
2476 && (blob_len <
2477 pSMBr->resp.ByteCount))) {
2478
2479 if (pSMBr->resp.hdr.WordCount == 4) {
2480 bcc_ptr += blob_len;
2481 cFYI(1,
2482 ("Security Blob Length %d ",
2483 blob_len));
2484 }
2485
2486 cFYI(1, ("NTLMSSP Challenge rcvd "));
2487
2488 memcpy(ses->server->cryptKey,
2489 SecurityBlob2->Challenge,
2490 CIFS_CRYPTO_KEY_SIZE);
2491 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2492 *pNTLMv2_flag = TRUE;
2493
2494 if((SecurityBlob2->NegotiateFlags &
2495 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2496 || (sign_CIFS_PDUs > 1))
2497 ses->server->secMode |=
2498 SECMODE_SIGN_REQUIRED;
2499 if ((SecurityBlob2->NegotiateFlags &
2500 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2501 ses->server->secMode |=
2502 SECMODE_SIGN_ENABLED;
2503
2504 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2505 if ((long) (bcc_ptr) % 2) {
2506 remaining_words =
2507 (BCC(smb_buffer_response)
2508 - 1) / 2;
2509 bcc_ptr++; /* Unicode strings must be word aligned */
2510 } else {
2511 remaining_words =
2512 BCC
2513 (smb_buffer_response) / 2;
2514 }
2515 len =
2516 UniStrnlen((wchar_t *) bcc_ptr,
2517 remaining_words - 1);
2518/* We look for obvious messed up bcc or strings in response so we do not go off
2519 the end since (at least) WIN2K and Windows XP have a major bug in not null
2520 terminating last Unicode string in response */
2521 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002522 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 cifs_strfromUCS_le(ses->serverOS,
2524 (wchar_t *)
2525 bcc_ptr, len,
2526 nls_codepage);
2527 bcc_ptr += 2 * (len + 1);
2528 remaining_words -= len + 1;
2529 ses->serverOS[2 * len] = 0;
2530 ses->serverOS[1 + (2 * len)] = 0;
2531 if (remaining_words > 0) {
2532 len = UniStrnlen((wchar_t *)
2533 bcc_ptr,
2534 remaining_words
2535 - 1);
2536 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002537 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 GFP_KERNEL);
2539 cifs_strfromUCS_le(ses->
2540 serverNOS,
2541 (wchar_t *)
2542 bcc_ptr,
2543 len,
2544 nls_codepage);
2545 bcc_ptr += 2 * (len + 1);
2546 ses->serverNOS[2 * len] = 0;
2547 ses->serverNOS[1 +
2548 (2 * len)] = 0;
2549 remaining_words -= len + 1;
2550 if (remaining_words > 0) {
2551 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2552 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2553 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002554 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 (len +
2556 1),
2557 GFP_KERNEL);
2558 cifs_strfromUCS_le
2559 (ses->
2560 serverDomain,
2561 (wchar_t *)
2562 bcc_ptr, len,
2563 nls_codepage);
2564 bcc_ptr +=
2565 2 * (len + 1);
2566 ses->
2567 serverDomain[2
2568 * len]
2569 = 0;
2570 ses->
2571 serverDomain[1
2572 +
2573 (2
2574 *
2575 len)]
2576 = 0;
2577 } /* else no more room so create dummy domain string */
2578 else
2579 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002580 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 GFP_KERNEL);
2582 } else { /* no room so create dummy domain and NOS string */
2583 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002584 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002586 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 }
2588 } else { /* ASCII */
2589 len = strnlen(bcc_ptr, 1024);
2590 if (((long) bcc_ptr + len) - (long)
2591 pByteArea(smb_buffer_response)
2592 <= BCC(smb_buffer_response)) {
2593 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002594 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 GFP_KERNEL);
2596 strncpy(ses->serverOS,
2597 bcc_ptr, len);
2598
2599 bcc_ptr += len;
2600 bcc_ptr[0] = 0; /* null terminate string */
2601 bcc_ptr++;
2602
2603 len = strnlen(bcc_ptr, 1024);
2604 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002605 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 GFP_KERNEL);
2607 strncpy(ses->serverNOS, bcc_ptr, len);
2608 bcc_ptr += len;
2609 bcc_ptr[0] = 0;
2610 bcc_ptr++;
2611
2612 len = strnlen(bcc_ptr, 1024);
2613 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002614 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 GFP_KERNEL);
2616 strncpy(ses->serverDomain, bcc_ptr, len);
2617 bcc_ptr += len;
2618 bcc_ptr[0] = 0;
2619 bcc_ptr++;
2620 } else
2621 cFYI(1,
2622 ("Variable field of length %d extends beyond end of smb ",
2623 len));
2624 }
2625 } else {
2626 cERROR(1,
2627 (" Security Blob Length extends beyond end of SMB"));
2628 }
2629 } else {
2630 cERROR(1, ("No session structure passed in."));
2631 }
2632 } else {
2633 cERROR(1,
2634 (" Invalid Word count %d: ",
2635 smb_buffer_response->WordCount));
2636 rc = -EIO;
2637 }
2638
2639 if (smb_buffer)
2640 cifs_buf_release(smb_buffer);
2641
2642 return rc;
2643}
2644static int
2645CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2646 char *ntlm_session_key, int ntlmv2_flag,
2647 const struct nls_table *nls_codepage)
2648{
2649 struct smb_hdr *smb_buffer;
2650 struct smb_hdr *smb_buffer_response;
2651 SESSION_SETUP_ANDX *pSMB;
2652 SESSION_SETUP_ANDX *pSMBr;
2653 char *bcc_ptr;
2654 char *user;
2655 char *domain;
2656 int rc = 0;
2657 int remaining_words = 0;
2658 int bytes_returned = 0;
2659 int len;
2660 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2661 PAUTHENTICATE_MESSAGE SecurityBlob;
2662 __u32 negotiate_flags, capabilities;
2663 __u16 count;
2664
2665 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2666 if(ses == NULL)
2667 return -EINVAL;
2668 user = ses->userName;
2669 domain = ses->domainName;
2670 smb_buffer = cifs_buf_get();
2671 if (smb_buffer == NULL) {
2672 return -ENOMEM;
2673 }
2674 smb_buffer_response = smb_buffer;
2675 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2676 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2677
2678 /* send SMBsessionSetup here */
2679 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2680 NULL /* no tCon exists yet */ , 12 /* wct */ );
2681 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2682 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2683 pSMB->req.AndXCommand = 0xFF;
2684 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2685 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2686
2687 pSMB->req.hdr.Uid = ses->Suid;
2688
2689 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2690 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2691
2692 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2693 CAP_EXTENDED_SECURITY;
2694 if (ses->capabilities & CAP_UNICODE) {
2695 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2696 capabilities |= CAP_UNICODE;
2697 }
2698 if (ses->capabilities & CAP_STATUS32) {
2699 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2700 capabilities |= CAP_STATUS32;
2701 }
2702 if (ses->capabilities & CAP_DFS) {
2703 smb_buffer->Flags2 |= SMBFLG2_DFS;
2704 capabilities |= CAP_DFS;
2705 }
2706 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2707
2708 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2709 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2710 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2711 SecurityBlob->MessageType = NtLmAuthenticate;
2712 bcc_ptr += SecurityBlobLength;
2713 negotiate_flags =
2714 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2715 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2716 0x80000000 | NTLMSSP_NEGOTIATE_128;
2717 if(sign_CIFS_PDUs)
2718 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2719 if(ntlmv2_flag)
2720 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2721
2722/* setup pointers to domain name and workstation name */
2723
2724 SecurityBlob->WorkstationName.Buffer = 0;
2725 SecurityBlob->WorkstationName.Length = 0;
2726 SecurityBlob->WorkstationName.MaximumLength = 0;
2727 SecurityBlob->SessionKey.Length = 0;
2728 SecurityBlob->SessionKey.MaximumLength = 0;
2729 SecurityBlob->SessionKey.Buffer = 0;
2730
2731 SecurityBlob->LmChallengeResponse.Length = 0;
2732 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2733 SecurityBlob->LmChallengeResponse.Buffer = 0;
2734
2735 SecurityBlob->NtChallengeResponse.Length =
2736 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2737 SecurityBlob->NtChallengeResponse.MaximumLength =
2738 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2739 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2740 SecurityBlob->NtChallengeResponse.Buffer =
2741 cpu_to_le32(SecurityBlobLength);
2742 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2743 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2744
2745 if (ses->capabilities & CAP_UNICODE) {
2746 if (domain == NULL) {
2747 SecurityBlob->DomainName.Buffer = 0;
2748 SecurityBlob->DomainName.Length = 0;
2749 SecurityBlob->DomainName.MaximumLength = 0;
2750 } else {
2751 __u16 len =
2752 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2753 nls_codepage);
2754 len *= 2;
2755 SecurityBlob->DomainName.MaximumLength =
2756 cpu_to_le16(len);
2757 SecurityBlob->DomainName.Buffer =
2758 cpu_to_le32(SecurityBlobLength);
2759 bcc_ptr += len;
2760 SecurityBlobLength += len;
2761 SecurityBlob->DomainName.Length =
2762 cpu_to_le16(len);
2763 }
2764 if (user == NULL) {
2765 SecurityBlob->UserName.Buffer = 0;
2766 SecurityBlob->UserName.Length = 0;
2767 SecurityBlob->UserName.MaximumLength = 0;
2768 } else {
2769 __u16 len =
2770 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2771 nls_codepage);
2772 len *= 2;
2773 SecurityBlob->UserName.MaximumLength =
2774 cpu_to_le16(len);
2775 SecurityBlob->UserName.Buffer =
2776 cpu_to_le32(SecurityBlobLength);
2777 bcc_ptr += len;
2778 SecurityBlobLength += len;
2779 SecurityBlob->UserName.Length =
2780 cpu_to_le16(len);
2781 }
2782
2783 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2784 SecurityBlob->WorkstationName.Length *= 2;
2785 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2786 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2787 bcc_ptr += SecurityBlob->WorkstationName.Length;
2788 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2789 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2790
2791 if ((long) bcc_ptr % 2) {
2792 *bcc_ptr = 0;
2793 bcc_ptr++;
2794 }
2795 bytes_returned =
2796 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2797 32, nls_codepage);
2798 bcc_ptr += 2 * bytes_returned;
2799 bytes_returned =
2800 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2801 nls_codepage);
2802 bcc_ptr += 2 * bytes_returned;
2803 bcc_ptr += 2; /* null term version string */
2804 bytes_returned =
2805 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2806 64, nls_codepage);
2807 bcc_ptr += 2 * bytes_returned;
2808 *(bcc_ptr + 1) = 0;
2809 *(bcc_ptr + 2) = 0;
2810 bcc_ptr += 2; /* null terminate network opsys string */
2811 *(bcc_ptr + 1) = 0;
2812 *(bcc_ptr + 2) = 0;
2813 bcc_ptr += 2; /* null domain */
2814 } else { /* ASCII */
2815 if (domain == NULL) {
2816 SecurityBlob->DomainName.Buffer = 0;
2817 SecurityBlob->DomainName.Length = 0;
2818 SecurityBlob->DomainName.MaximumLength = 0;
2819 } else {
2820 __u16 len;
2821 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2822 strncpy(bcc_ptr, domain, 63);
2823 len = strnlen(domain, 64);
2824 SecurityBlob->DomainName.MaximumLength =
2825 cpu_to_le16(len);
2826 SecurityBlob->DomainName.Buffer =
2827 cpu_to_le32(SecurityBlobLength);
2828 bcc_ptr += len;
2829 SecurityBlobLength += len;
2830 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2831 }
2832 if (user == NULL) {
2833 SecurityBlob->UserName.Buffer = 0;
2834 SecurityBlob->UserName.Length = 0;
2835 SecurityBlob->UserName.MaximumLength = 0;
2836 } else {
2837 __u16 len;
2838 strncpy(bcc_ptr, user, 63);
2839 len = strnlen(user, 64);
2840 SecurityBlob->UserName.MaximumLength =
2841 cpu_to_le16(len);
2842 SecurityBlob->UserName.Buffer =
2843 cpu_to_le32(SecurityBlobLength);
2844 bcc_ptr += len;
2845 SecurityBlobLength += len;
2846 SecurityBlob->UserName.Length = cpu_to_le16(len);
2847 }
2848 /* BB fill in our workstation name if known BB */
2849
2850 strcpy(bcc_ptr, "Linux version ");
2851 bcc_ptr += strlen("Linux version ");
2852 strcpy(bcc_ptr, system_utsname.release);
2853 bcc_ptr += strlen(system_utsname.release) + 1;
2854 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2855 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2856 bcc_ptr++; /* null domain */
2857 *bcc_ptr = 0;
2858 }
2859 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2860 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2861 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2862 smb_buffer->smb_buf_length += count;
2863 pSMB->req.ByteCount = cpu_to_le16(count);
2864
2865 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2866 &bytes_returned, 1);
2867 if (rc) {
2868/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2869 } else if ((smb_buffer_response->WordCount == 3)
2870 || (smb_buffer_response->WordCount == 4)) {
2871 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2872 __u16 blob_len =
2873 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2874 if (action & GUEST_LOGIN)
2875 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2876/* if(SecurityBlob2->MessageType != NtLm??){
2877 cFYI("Unexpected message type on auth response is %d "));
2878 } */
2879 if (ses) {
2880 cFYI(1,
2881 ("Does UID on challenge %d match auth response UID %d ",
2882 ses->Suid, smb_buffer_response->Uid));
2883 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2884 bcc_ptr = pByteArea(smb_buffer_response);
2885 /* response can have either 3 or 4 word count - Samba sends 3 */
2886 if ((pSMBr->resp.hdr.WordCount == 3)
2887 || ((pSMBr->resp.hdr.WordCount == 4)
2888 && (blob_len <
2889 pSMBr->resp.ByteCount))) {
2890 if (pSMBr->resp.hdr.WordCount == 4) {
2891 bcc_ptr +=
2892 blob_len;
2893 cFYI(1,
2894 ("Security Blob Length %d ",
2895 blob_len));
2896 }
2897
2898 cFYI(1,
2899 ("NTLMSSP response to Authenticate "));
2900
2901 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2902 if ((long) (bcc_ptr) % 2) {
2903 remaining_words =
2904 (BCC(smb_buffer_response)
2905 - 1) / 2;
2906 bcc_ptr++; /* Unicode strings must be word aligned */
2907 } else {
2908 remaining_words = BCC(smb_buffer_response) / 2;
2909 }
2910 len =
2911 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2912/* We look for obvious messed up bcc or strings in response so we do not go off
2913 the end since (at least) WIN2K and Windows XP have a major bug in not null
2914 terminating last Unicode string in response */
2915 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002916 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 cifs_strfromUCS_le(ses->serverOS,
2918 (wchar_t *)
2919 bcc_ptr, len,
2920 nls_codepage);
2921 bcc_ptr += 2 * (len + 1);
2922 remaining_words -= len + 1;
2923 ses->serverOS[2 * len] = 0;
2924 ses->serverOS[1 + (2 * len)] = 0;
2925 if (remaining_words > 0) {
2926 len = UniStrnlen((wchar_t *)
2927 bcc_ptr,
2928 remaining_words
2929 - 1);
2930 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002931 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 GFP_KERNEL);
2933 cifs_strfromUCS_le(ses->
2934 serverNOS,
2935 (wchar_t *)
2936 bcc_ptr,
2937 len,
2938 nls_codepage);
2939 bcc_ptr += 2 * (len + 1);
2940 ses->serverNOS[2 * len] = 0;
2941 ses->serverNOS[1+(2*len)] = 0;
2942 remaining_words -= len + 1;
2943 if (remaining_words > 0) {
2944 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2945 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2946 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002947 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 (len +
2949 1),
2950 GFP_KERNEL);
2951 cifs_strfromUCS_le
2952 (ses->
2953 serverDomain,
2954 (wchar_t *)
2955 bcc_ptr, len,
2956 nls_codepage);
2957 bcc_ptr +=
2958 2 * (len + 1);
2959 ses->
2960 serverDomain[2
2961 * len]
2962 = 0;
2963 ses->
2964 serverDomain[1
2965 +
2966 (2
2967 *
2968 len)]
2969 = 0;
2970 } /* else no more room so create dummy domain string */
2971 else
Steve French433dc242005-04-28 22:41:08 -07002972 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002974 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2975 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 }
2977 } else { /* ASCII */
2978 len = strnlen(bcc_ptr, 1024);
2979 if (((long) bcc_ptr + len) -
2980 (long) pByteArea(smb_buffer_response)
2981 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002982 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 strncpy(ses->serverOS,bcc_ptr, len);
2984
2985 bcc_ptr += len;
2986 bcc_ptr[0] = 0; /* null terminate the string */
2987 bcc_ptr++;
2988
2989 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002990 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 strncpy(ses->serverNOS, bcc_ptr, len);
2992 bcc_ptr += len;
2993 bcc_ptr[0] = 0;
2994 bcc_ptr++;
2995
2996 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002997 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 strncpy(ses->serverDomain, bcc_ptr, len);
2999 bcc_ptr += len;
3000 bcc_ptr[0] = 0;
3001 bcc_ptr++;
3002 } else
3003 cFYI(1,
3004 ("Variable field of length %d extends beyond end of smb ",
3005 len));
3006 }
3007 } else {
3008 cERROR(1,
3009 (" Security Blob Length extends beyond end of SMB"));
3010 }
3011 } else {
3012 cERROR(1, ("No session structure passed in."));
3013 }
3014 } else {
3015 cERROR(1,
3016 (" Invalid Word count %d: ",
3017 smb_buffer_response->WordCount));
3018 rc = -EIO;
3019 }
3020
3021 if (smb_buffer)
3022 cifs_buf_release(smb_buffer);
3023
3024 return rc;
3025}
3026
3027int
3028CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3029 const char *tree, struct cifsTconInfo *tcon,
3030 const struct nls_table *nls_codepage)
3031{
3032 struct smb_hdr *smb_buffer;
3033 struct smb_hdr *smb_buffer_response;
3034 TCONX_REQ *pSMB;
3035 TCONX_RSP *pSMBr;
3036 unsigned char *bcc_ptr;
3037 int rc = 0;
3038 int length;
3039 __u16 count;
3040
3041 if (ses == NULL)
3042 return -EIO;
3043
3044 smb_buffer = cifs_buf_get();
3045 if (smb_buffer == NULL) {
3046 return -ENOMEM;
3047 }
3048 smb_buffer_response = smb_buffer;
3049
3050 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3051 NULL /*no tid */ , 4 /*wct */ );
3052 smb_buffer->Uid = ses->Suid;
3053 pSMB = (TCONX_REQ *) smb_buffer;
3054 pSMBr = (TCONX_RSP *) smb_buffer_response;
3055
3056 pSMB->AndXCommand = 0xFF;
3057 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3058 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3059 bcc_ptr = &pSMB->Password[0];
3060 bcc_ptr++; /* skip password */
3061
3062 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3063 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3064
3065 if (ses->capabilities & CAP_STATUS32) {
3066 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3067 }
3068 if (ses->capabilities & CAP_DFS) {
3069 smb_buffer->Flags2 |= SMBFLG2_DFS;
3070 }
3071 if (ses->capabilities & CAP_UNICODE) {
3072 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3073 length =
3074 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3075 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3076 bcc_ptr += 2; /* skip trailing null */
3077 } else { /* ASCII */
3078
3079 strcpy(bcc_ptr, tree);
3080 bcc_ptr += strlen(tree) + 1;
3081 }
3082 strcpy(bcc_ptr, "?????");
3083 bcc_ptr += strlen("?????");
3084 bcc_ptr += 1;
3085 count = bcc_ptr - &pSMB->Password[0];
3086 pSMB->hdr.smb_buf_length += count;
3087 pSMB->ByteCount = cpu_to_le16(count);
3088
3089 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3090
3091 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3092 /* above now done in SendReceive */
3093 if ((rc == 0) && (tcon != NULL)) {
3094 tcon->tidStatus = CifsGood;
3095 tcon->tid = smb_buffer_response->Tid;
3096 bcc_ptr = pByteArea(smb_buffer_response);
3097 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3098 /* skip service field (NB: this field is always ASCII) */
3099 bcc_ptr += length + 1;
3100 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3101 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3102 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3103 if ((bcc_ptr + (2 * length)) -
3104 pByteArea(smb_buffer_response) <=
3105 BCC(smb_buffer_response)) {
3106 if(tcon->nativeFileSystem)
3107 kfree(tcon->nativeFileSystem);
3108 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003109 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 cifs_strfromUCS_le(tcon->nativeFileSystem,
3111 (wchar_t *) bcc_ptr,
3112 length, nls_codepage);
3113 bcc_ptr += 2 * length;
3114 bcc_ptr[0] = 0; /* null terminate the string */
3115 bcc_ptr[1] = 0;
3116 bcc_ptr += 2;
3117 }
3118 /* else do not bother copying these informational fields */
3119 } else {
3120 length = strnlen(bcc_ptr, 1024);
3121 if ((bcc_ptr + length) -
3122 pByteArea(smb_buffer_response) <=
3123 BCC(smb_buffer_response)) {
3124 if(tcon->nativeFileSystem)
3125 kfree(tcon->nativeFileSystem);
3126 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003127 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 strncpy(tcon->nativeFileSystem, bcc_ptr,
3129 length);
3130 }
3131 /* else do not bother copying these informational fields */
3132 }
3133 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3134 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3135 } else if ((rc == 0) && tcon == NULL) {
3136 /* all we need to save for IPC$ connection */
3137 ses->ipc_tid = smb_buffer_response->Tid;
3138 }
3139
3140 if (smb_buffer)
3141 cifs_buf_release(smb_buffer);
3142 return rc;
3143}
3144
3145int
3146cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3147{
3148 int rc = 0;
3149 int xid;
3150 struct cifsSesInfo *ses = NULL;
3151 struct task_struct *cifsd_task;
3152
3153 xid = GetXid();
3154
3155 if (cifs_sb->tcon) {
3156 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3157 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3158 if (rc == -EBUSY) {
3159 FreeXid(xid);
3160 return 0;
3161 }
3162 tconInfoFree(cifs_sb->tcon);
3163 if ((ses) && (ses->server)) {
3164 /* save off task so we do not refer to ses later */
3165 cifsd_task = ses->server->tsk;
3166 cFYI(1, ("About to do SMBLogoff "));
3167 rc = CIFSSMBLogoff(xid, ses);
3168 if (rc == -EBUSY) {
3169 FreeXid(xid);
3170 return 0;
3171 } else if (rc == -ESHUTDOWN) {
3172 cFYI(1,("Waking up socket by sending it signal"));
3173 if(cifsd_task)
3174 send_sig(SIGKILL,cifsd_task,1);
3175 rc = 0;
3176 } /* else - we have an smb session
3177 left on this socket do not kill cifsd */
3178 } else
3179 cFYI(1, ("No session or bad tcon"));
3180 }
3181
3182 cifs_sb->tcon = NULL;
3183 if (ses) {
3184 set_current_state(TASK_INTERRUPTIBLE);
3185 schedule_timeout(HZ / 2);
3186 }
3187 if (ses)
3188 sesInfoFree(ses);
3189
3190 FreeXid(xid);
3191 return rc; /* BB check if we should always return zero here */
3192}
3193
3194int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3195 struct nls_table * nls_info)
3196{
3197 int rc = 0;
3198 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3199 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003200 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
3202 /* what if server changes its buffer size after dropping the session? */
3203 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3204 rc = CIFSSMBNegotiate(xid, pSesInfo);
3205 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3206 rc = CIFSSMBNegotiate(xid, pSesInfo);
3207 if(rc == -EAGAIN)
3208 rc = -EHOSTDOWN;
3209 }
3210 if(rc == 0) {
3211 spin_lock(&GlobalMid_Lock);
3212 if(pSesInfo->server->tcpStatus != CifsExiting)
3213 pSesInfo->server->tcpStatus = CifsGood;
3214 else
3215 rc = -EHOSTDOWN;
3216 spin_unlock(&GlobalMid_Lock);
3217
3218 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003219 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 }
3221 if (!rc) {
3222 pSesInfo->capabilities = pSesInfo->server->capabilities;
3223 if(linuxExtEnabled == 0)
3224 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003225 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3227 pSesInfo->server->secMode,
3228 pSesInfo->server->capabilities,
3229 pSesInfo->server->timeZone));
3230 if (extended_security
3231 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3232 && (pSesInfo->server->secType == NTLMSSP)) {
3233 cFYI(1, ("New style sesssetup "));
3234 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3235 NULL /* security blob */,
3236 0 /* blob length */,
3237 nls_info);
3238 } else if (extended_security
3239 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3240 && (pSesInfo->server->secType == RawNTLMSSP)) {
3241 cFYI(1, ("NTLMSSP sesssetup "));
3242 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3243 pSesInfo,
3244 &ntlmv2_flag,
3245 nls_info);
3246 if (!rc) {
3247 if(ntlmv2_flag) {
3248 char * v2_response;
3249 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3250 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3251 nls_info)) {
3252 rc = -ENOMEM;
3253 goto ss_err_exit;
3254 } else
3255 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3256 if(v2_response) {
3257 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003258 /* if(first_time)
3259 cifs_calculate_ntlmv2_mac_key(
3260 pSesInfo->server->mac_signing_key,
3261 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 kfree(v2_response);
3263 /* BB Put dummy sig in SessSetup PDU? */
3264 } else {
3265 rc = -ENOMEM;
3266 goto ss_err_exit;
3267 }
3268
3269 } else {
3270 SMBNTencrypt(pSesInfo->password,
3271 pSesInfo->server->cryptKey,
3272 ntlm_session_key);
3273
Steve Frenchad009ac2005-04-28 22:41:05 -07003274 if(first_time)
3275 cifs_calculate_mac_key(
3276 pSesInfo->server->mac_signing_key,
3277 ntlm_session_key,
3278 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 }
3280 /* for better security the weaker lanman hash not sent
3281 in AuthSessSetup so we no longer calculate it */
3282
3283 rc = CIFSNTLMSSPAuthSessSetup(xid,
3284 pSesInfo,
3285 ntlm_session_key,
3286 ntlmv2_flag,
3287 nls_info);
3288 }
3289 } else { /* old style NTLM 0.12 session setup */
3290 SMBNTencrypt(pSesInfo->password,
3291 pSesInfo->server->cryptKey,
3292 ntlm_session_key);
3293
Steve Frenchad009ac2005-04-28 22:41:05 -07003294 if(first_time)
3295 cifs_calculate_mac_key(
3296 pSesInfo->server->mac_signing_key,
3297 ntlm_session_key, pSesInfo->password);
3298
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 rc = CIFSSessSetup(xid, pSesInfo,
3300 ntlm_session_key, nls_info);
3301 }
3302 if (rc) {
3303 cERROR(1,("Send error in SessSetup = %d",rc));
3304 } else {
3305 cFYI(1,("CIFS Session Established successfully"));
3306 pSesInfo->status = CifsGood;
3307 }
3308 }
3309ss_err_exit:
3310 return rc;
3311}
3312