[PATCH] ARM: 2847/1: S3C24XX - Documentation for USB OHCI host
[linux-2.6/kvm.git] / fs / cifs / connect.c
blobe568cc47a7f93005518d1470696f89ee1444a1ae
1 /*
2 * fs/cifs/connect.c
4 * Copyright (C) International Business Machines Corp., 2002,2005
5 * Author(s): Steve French (sfrench@us.ibm.com)
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.
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.
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
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>
31 #include <linux/delay.h>
32 #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"
44 #define CIFS_PORT 445
45 #define RFC1001_PORT 139
47 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
48 unsigned char *p24);
49 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
50 unsigned char *p24);
52 extern mempool_t *cifs_req_poolp;
54 struct 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;
76 unsigned remap:1; /* set to remap seven reserved chars in filenames */
77 unsigned int rsize;
78 unsigned int wsize;
79 unsigned int sockopt;
80 unsigned short int port;
83 static int ipv4_connect(struct sockaddr_in *psin_server,
84 struct socket **csocket,
85 char * netb_name);
86 static int ipv6_connect(struct sockaddr_in6 *psin_server,
87 struct socket **csocket);
90 /*
91 * cifs tcp session reconnection
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)
99 int
100 cifs_reconnect(struct TCP_Server_Info *server)
102 int rc = 0;
103 struct list_head *tmp;
104 struct cifsSesInfo *ses;
105 struct cifsTconInfo *tcon;
106 struct mid_q_entry * mid_entry;
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;
119 cFYI(1, ("Reconnecting tcp session"));
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;
132 /* else tcp and smb sessions need reconnection */
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;
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;
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) {
160 /* 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 */
164 mid_entry->midState = MID_RETRY_NEEDED;
168 spin_unlock(&GlobalMid_Lock);
169 up(&server->tcpSem);
171 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
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);
180 if(rc) {
181 msleep(3000);
182 } else {
183 atomic_inc(&tcpSesReconnectCount);
184 spin_lock(&GlobalMid_Lock);
185 if(server->tcpStatus != CifsExiting)
186 server->tcpStatus = CifsGood;
187 server->sequence_number = 0;
188 spin_unlock(&GlobalMid_Lock);
189 /* atomic_set(&server->inFlight,0);*/
190 wake_up(&server->response_q);
193 return rc;
197 return codes:
198 0 not a transact2, or all data present
199 >0 transact2 with that much data missing
200 -EINVAL = invalid transact2
203 static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
205 struct smb_t2_rsp * pSMBt;
206 int total_data_size;
207 int data_in_this_rsp;
208 int remaining;
210 if(pSMB->Command != SMB_COM_TRANSACTION2)
211 return 0;
213 /* check for plausible wct, bcc and t2 data and parm sizes */
214 /* check for parm and data offset going beyond end of smb */
215 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
216 cFYI(1,("invalid transact2 word count"));
217 return -EINVAL;
220 pSMBt = (struct smb_t2_rsp *)pSMB;
222 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
223 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
225 remaining = total_data_size - data_in_this_rsp;
227 if(remaining == 0)
228 return 0;
229 else if(remaining < 0) {
230 cFYI(1,("total data %d smaller than data in frame %d",
231 total_data_size, data_in_this_rsp));
232 return -EINVAL;
233 } else {
234 cFYI(1,("missing %d bytes from transact2, check next response",
235 remaining));
236 if(total_data_size > maxBufSize) {
237 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
238 total_data_size,maxBufSize));
239 return -EINVAL;
241 return remaining;
245 static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
247 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
248 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
249 int total_data_size;
250 int total_in_buf;
251 int remaining;
252 int total_in_buf2;
253 char * data_area_of_target;
254 char * data_area_of_buf2;
255 __u16 byte_count;
257 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
259 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
260 cFYI(1,("total data sizes of primary and secondary t2 differ"));
263 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
265 remaining = total_data_size - total_in_buf;
267 if(remaining < 0)
268 return -EINVAL;
270 if(remaining == 0) /* nothing to do, ignore */
271 return 0;
273 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
274 if(remaining < total_in_buf2) {
275 cFYI(1,("transact2 2nd response contains too much data"));
278 /* find end of first SMB data area */
279 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
280 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
281 /* validate target area */
283 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
284 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
286 data_area_of_target += total_in_buf;
288 /* copy second buffer into end of first buffer */
289 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
290 total_in_buf += total_in_buf2;
291 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
292 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
293 byte_count += total_in_buf2;
294 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
296 byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
297 byte_count += total_in_buf2;
299 /* BB also add check that we are not beyond maximum buffer size */
301 pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
303 if(remaining == total_in_buf2) {
304 cFYI(1,("found the last secondary response"));
305 return 0; /* we are done */
306 } else /* more responses to go */
307 return 1;
311 static int
312 cifs_demultiplex_thread(struct TCP_Server_Info *server)
314 int length;
315 unsigned int pdu_length, total_read;
316 struct smb_hdr *smb_buffer = NULL;
317 struct smb_hdr *bigbuf = NULL;
318 struct smb_hdr *smallbuf = NULL;
319 struct msghdr smb_msg;
320 struct kvec iov;
321 struct socket *csocket = server->ssocket;
322 struct list_head *tmp;
323 struct cifsSesInfo *ses;
324 struct task_struct *task_to_wake = NULL;
325 struct mid_q_entry *mid_entry;
326 char *temp;
327 int isLargeBuf = FALSE;
328 int isMultiRsp;
329 int reconnect;
331 daemonize("cifsd");
332 allow_signal(SIGKILL);
333 current->flags |= PF_MEMALLOC;
334 server->tsk = current; /* save process info to wake at shutdown */
335 cFYI(1, ("Demultiplex PID: %d", current->pid));
336 write_lock(&GlobalSMBSeslock);
337 atomic_inc(&tcpSesAllocCount);
338 length = tcpSesAllocCount.counter;
339 write_unlock(&GlobalSMBSeslock);
340 if(length > 1) {
341 mempool_resize(cifs_req_poolp,
342 length + cifs_min_rcv,
343 GFP_KERNEL);
346 while (server->tcpStatus != CifsExiting) {
347 if (bigbuf == NULL) {
348 bigbuf = cifs_buf_get();
349 if(bigbuf == NULL) {
350 cERROR(1,("No memory for large SMB response"));
351 msleep(3000);
352 /* retry will check if exiting */
353 continue;
355 } else if(isLargeBuf) {
356 /* we are reusing a dirtry large buf, clear its start */
357 memset(bigbuf, 0, sizeof (struct smb_hdr));
360 if (smallbuf == NULL) {
361 smallbuf = cifs_small_buf_get();
362 if(smallbuf == NULL) {
363 cERROR(1,("No memory for SMB response"));
364 msleep(1000);
365 /* retry will check if exiting */
366 continue;
368 /* beginning of smb buffer is cleared in our buf_get */
369 } else /* if existing small buf clear beginning */
370 memset(smallbuf, 0, sizeof (struct smb_hdr));
372 isLargeBuf = FALSE;
373 isMultiRsp = FALSE;
374 smb_buffer = smallbuf;
375 iov.iov_base = smb_buffer;
376 iov.iov_len = 4;
377 smb_msg.msg_control = NULL;
378 smb_msg.msg_controllen = 0;
379 length =
380 kernel_recvmsg(csocket, &smb_msg,
381 &iov, 1, 4, 0 /* BB see socket.h flags */);
383 if(server->tcpStatus == CifsExiting) {
384 break;
385 } else if (server->tcpStatus == CifsNeedReconnect) {
386 cFYI(1,("Reconnect after server stopped responding"));
387 cifs_reconnect(server);
388 cFYI(1,("call to reconnect done"));
389 csocket = server->ssocket;
390 continue;
391 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
392 msleep(1); /* minimum sleep to prevent looping
393 allowing socket to clear and app threads to set
394 tcpStatus CifsNeedReconnect if server hung */
395 continue;
396 } else if (length <= 0) {
397 if(server->tcpStatus == CifsNew) {
398 cFYI(1,("tcp session abend after SMBnegprot"));
399 /* some servers kill the TCP session rather than
400 returning an SMB negprot error, in which
401 case reconnecting here is not going to help,
402 and so simply return error to mount */
403 break;
405 if(length == -EINTR) {
406 cFYI(1,("cifsd thread killed"));
407 break;
409 cFYI(1,("Reconnect after unexpected peek error %d",
410 length));
411 cifs_reconnect(server);
412 csocket = server->ssocket;
413 wake_up(&server->response_q);
414 continue;
415 } else if (length < 4) {
416 cFYI(1,
417 ("Frame under four bytes received (%d bytes long)",
418 length));
419 cifs_reconnect(server);
420 csocket = server->ssocket;
421 wake_up(&server->response_q);
422 continue;
425 /* the right amount was read from socket - 4 bytes */
427 pdu_length = ntohl(smb_buffer->smb_buf_length);
428 cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
430 temp = (char *) smb_buffer;
431 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
432 continue;
433 } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
434 cFYI(1,("Good RFC 1002 session rsp"));
435 continue;
436 } 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 */
439 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
440 temp[4]));
441 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;
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;
470 /* else we have an SMB response */
471 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
472 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
473 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
474 length, pdu_length+4));
475 cifs_reconnect(server);
476 csocket = server->ssocket;
477 wake_up(&server->response_q);
478 continue;
481 /* else length ok */
482 reconnect = 0;
484 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
485 isLargeBuf = TRUE;
486 memcpy(bigbuf, smallbuf, 4);
487 smb_buffer = bigbuf;
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) {
502 cifs_reconnect(server);
503 csocket = server->ssocket;
504 /* 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*/
514 continue;
515 } 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;
524 if(reconnect == 2)
525 break;
526 else if(reconnect == 1)
527 continue;
529 length += 4; /* account for rfc1002 hdr */
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;
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);
544 if ((mid_entry->mid == smb_buffer->Mid) &&
545 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
546 (mid_entry->command == smb_buffer->Command)) {
547 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
548 /* We have a multipart transact2 resp */
549 isMultiRsp = TRUE;
550 if(mid_entry->resp_buf) {
551 /* merge response - fix up 1st*/
552 if(coalesce_t2(smb_buffer,
553 mid_entry->resp_buf)) {
554 break;
555 } else {
556 /* all parts received */
557 goto multi_t2_fnd;
559 } else {
560 if(!isLargeBuf) {
561 cERROR(1,("1st trans2 resp needs bigbuf"));
562 /* BB maybe we can fix this up, switch
563 to already allocated large buffer? */
564 } else {
565 /* Have first buffer */
566 mid_entry->resp_buf =
567 smb_buffer;
568 mid_entry->largeBuf = 1;
569 bigbuf = NULL;
572 break;
574 mid_entry->resp_buf = smb_buffer;
575 if(isLargeBuf)
576 mid_entry->largeBuf = 1;
577 else
578 mid_entry->largeBuf = 0;
579 multi_t2_fnd:
580 task_to_wake = mid_entry->tsk;
581 mid_entry->midState = MID_RESPONSE_RECEIVED;
582 break;
585 spin_unlock(&GlobalMid_Lock);
586 if (task_to_wake) {
587 /* Was previous buf put in mpx struct for multi-rsp? */
588 if(!isMultiRsp) {
589 /* smb buffer will be freed by user thread */
590 if(isLargeBuf) {
591 bigbuf = NULL;
592 } else
593 smallbuf = NULL;
595 wake_up_process(task_to_wake);
596 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
597 && (isMultiRsp == FALSE)) {
598 cERROR(1, ("No task to wake, unknown frame rcvd!"));
599 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
601 } /* end while !EXITING */
603 spin_lock(&GlobalMid_Lock);
604 server->tcpStatus = CifsExiting;
605 server->tsk = NULL;
606 /* check if we have blocked requests that need to free */
607 /* Note that cifs_max_pending is normally 50, but
608 can be set at module install time to as little as two */
609 if(atomic_read(&server->inFlight) >= cifs_max_pending)
610 atomic_set(&server->inFlight, cifs_max_pending - 1);
611 /* We do not want to set the max_pending too low or we
612 could end up with the counter going negative */
613 spin_unlock(&GlobalMid_Lock);
614 /* Although there should not be any requests blocked on
615 this queue it can not hurt to be paranoid and try to wake up requests
616 that may haven been blocked when more than 50 at time were on the wire
617 to the same server - they now will see the session is in exit state
618 and get out of SendReceive. */
619 wake_up_all(&server->request_q);
620 /* give those requests time to exit */
621 msleep(125);
623 if(server->ssocket) {
624 sock_release(csocket);
625 server->ssocket = NULL;
627 /* buffer usuallly freed in free_mid - need to free it here on exit */
628 if (bigbuf != NULL)
629 cifs_buf_release(bigbuf);
630 if (smallbuf != NULL)
631 cifs_small_buf_release(smallbuf);
633 read_lock(&GlobalSMBSeslock);
634 if (list_empty(&server->pending_mid_q)) {
635 /* loop through server session structures attached to this and
636 mark them dead */
637 list_for_each(tmp, &GlobalSMBSessionList) {
638 ses =
639 list_entry(tmp, struct cifsSesInfo,
640 cifsSessionList);
641 if (ses->server == server) {
642 ses->status = CifsExiting;
643 ses->server = NULL;
646 read_unlock(&GlobalSMBSeslock);
647 } else {
648 /* although we can not zero the server struct pointer yet,
649 since there are active requests which may depnd on them,
650 mark the corresponding SMB sessions as exiting too */
651 list_for_each(tmp, &GlobalSMBSessionList) {
652 ses = list_entry(tmp, struct cifsSesInfo,
653 cifsSessionList);
654 if (ses->server == server) {
655 ses->status = CifsExiting;
659 spin_lock(&GlobalMid_Lock);
660 list_for_each(tmp, &server->pending_mid_q) {
661 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
662 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
663 cFYI(1,
664 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
665 task_to_wake = mid_entry->tsk;
666 if(task_to_wake) {
667 wake_up_process(task_to_wake);
671 spin_unlock(&GlobalMid_Lock);
672 read_unlock(&GlobalSMBSeslock);
673 /* 1/8th of sec is more than enough time for them to exit */
674 msleep(125);
677 if (list_empty(&server->pending_mid_q)) {
678 /* mpx threads have not exited yet give them
679 at least the smb send timeout time for long ops */
680 /* due to delays on oplock break requests, we need
681 to wait at least 45 seconds before giving up
682 on a request getting a response and going ahead
683 and killing cifsd */
684 cFYI(1, ("Wait for exit from demultiplex thread"));
685 msleep(46000);
686 /* if threads still have not exited they are probably never
687 coming home not much else we can do but free the memory */
690 write_lock(&GlobalSMBSeslock);
691 atomic_dec(&tcpSesAllocCount);
692 length = tcpSesAllocCount.counter;
694 /* last chance to mark ses pointers invalid
695 if there are any pointing to this (e.g
696 if a crazy root user tried to kill cifsd
697 kernel thread explicitly this might happen) */
698 list_for_each(tmp, &GlobalSMBSessionList) {
699 ses = list_entry(tmp, struct cifsSesInfo,
700 cifsSessionList);
701 if (ses->server == server) {
702 ses->server = NULL;
705 write_unlock(&GlobalSMBSeslock);
707 kfree(server);
708 if(length > 0) {
709 mempool_resize(cifs_req_poolp,
710 length + cifs_min_rcv,
711 GFP_KERNEL);
714 msleep(250);
715 return 0;
718 static int
719 cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
721 char *value;
722 char *data;
723 unsigned int temp_len, i, j;
724 char separator[2];
726 separator[0] = ',';
727 separator[1] = 0;
729 memset(vol->source_rfc1001_name,0x20,15);
730 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
731 /* does not have to be a perfect mapping since the field is
732 informational, only used for servers that do not support
733 port 445 and it can be overridden at mount time */
734 vol->source_rfc1001_name[i] =
735 toupper(system_utsname.nodename[i]);
737 vol->source_rfc1001_name[15] = 0;
739 vol->linux_uid = current->uid; /* current->euid instead? */
740 vol->linux_gid = current->gid;
741 vol->dir_mode = S_IRWXUGO;
742 /* 2767 perms indicate mandatory locking support */
743 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
745 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
746 vol->rw = TRUE;
748 if (!options)
749 return 1;
751 if(strncmp(options,"sep=",4) == 0) {
752 if(options[4] != 0) {
753 separator[0] = options[4];
754 options += 5;
755 } else {
756 cFYI(1,("Null separator not allowed"));
760 while ((data = strsep(&options, separator)) != NULL) {
761 if (!*data)
762 continue;
763 if ((value = strchr(data, '=')) != NULL)
764 *value++ = '\0';
766 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
767 vol->no_xattr = 0;
768 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
769 vol->no_xattr = 1;
770 } else if (strnicmp(data, "user", 4) == 0) {
771 if (!value || !*value) {
772 printk(KERN_WARNING
773 "CIFS: invalid or missing username\n");
774 return 1; /* needs_arg; */
776 if (strnlen(value, 200) < 200) {
777 vol->username = value;
778 } else {
779 printk(KERN_WARNING "CIFS: username too long\n");
780 return 1;
782 } else if (strnicmp(data, "pass", 4) == 0) {
783 if (!value) {
784 vol->password = NULL;
785 continue;
786 } else if(value[0] == 0) {
787 /* check if string begins with double comma
788 since that would mean the password really
789 does start with a comma, and would not
790 indicate an empty string */
791 if(value[1] != separator[0]) {
792 vol->password = NULL;
793 continue;
796 temp_len = strlen(value);
797 /* removed password length check, NTLM passwords
798 can be arbitrarily long */
800 /* if comma in password, the string will be
801 prematurely null terminated. Commas in password are
802 specified across the cifs mount interface by a double
803 comma ie ,, and a comma used as in other cases ie ','
804 as a parameter delimiter/separator is single and due
805 to the strsep above is temporarily zeroed. */
807 /* NB: password legally can have multiple commas and
808 the only illegal character in a password is null */
810 if ((value[temp_len] == 0) &&
811 (value[temp_len+1] == separator[0])) {
812 /* reinsert comma */
813 value[temp_len] = separator[0];
814 temp_len+=2; /* move after the second comma */
815 while(value[temp_len] != 0) {
816 if (value[temp_len] == separator[0]) {
817 if (value[temp_len+1] ==
818 separator[0]) {
819 /* skip second comma */
820 temp_len++;
821 } else {
822 /* single comma indicating start
823 of next parm */
824 break;
827 temp_len++;
829 if(value[temp_len] == 0) {
830 options = NULL;
831 } else {
832 value[temp_len] = 0;
833 /* point option to start of next parm */
834 options = value + temp_len + 1;
836 /* go from value to value + temp_len condensing
837 double commas to singles. Note that this ends up
838 allocating a few bytes too many, which is ok */
839 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
840 if(vol->password == NULL) {
841 printk("CIFS: no memory for pass\n");
842 return 1;
844 for(i=0,j=0;i<temp_len;i++,j++) {
845 vol->password[j] = value[i];
846 if(value[i] == separator[0]
847 && value[i+1] == separator[0]) {
848 /* skip second comma */
849 i++;
852 vol->password[j] = 0;
853 } else {
854 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
855 if(vol->password == NULL) {
856 printk("CIFS: no memory for pass\n");
857 return 1;
859 strcpy(vol->password, value);
861 } else if (strnicmp(data, "ip", 2) == 0) {
862 if (!value || !*value) {
863 vol->UNCip = NULL;
864 } else if (strnlen(value, 35) < 35) {
865 vol->UNCip = value;
866 } else {
867 printk(KERN_WARNING "CIFS: ip address too long\n");
868 return 1;
870 } else if ((strnicmp(data, "unc", 3) == 0)
871 || (strnicmp(data, "target", 6) == 0)
872 || (strnicmp(data, "path", 4) == 0)) {
873 if (!value || !*value) {
874 printk(KERN_WARNING
875 "CIFS: invalid path to network resource\n");
876 return 1; /* needs_arg; */
878 if ((temp_len = strnlen(value, 300)) < 300) {
879 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
880 if(vol->UNC == NULL)
881 return 1;
882 strcpy(vol->UNC,value);
883 if (strncmp(vol->UNC, "//", 2) == 0) {
884 vol->UNC[0] = '\\';
885 vol->UNC[1] = '\\';
886 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
887 printk(KERN_WARNING
888 "CIFS: UNC Path does not begin with // or \\\\ \n");
889 return 1;
891 } else {
892 printk(KERN_WARNING "CIFS: UNC name too long\n");
893 return 1;
895 } else if ((strnicmp(data, "domain", 3) == 0)
896 || (strnicmp(data, "workgroup", 5) == 0)) {
897 if (!value || !*value) {
898 printk(KERN_WARNING "CIFS: invalid domain name\n");
899 return 1; /* needs_arg; */
901 /* BB are there cases in which a comma can be valid in
902 a domain name and need special handling? */
903 if (strnlen(value, 65) < 65) {
904 vol->domainname = value;
905 cFYI(1, ("Domain name set"));
906 } else {
907 printk(KERN_WARNING "CIFS: domain name too long\n");
908 return 1;
910 } else if (strnicmp(data, "iocharset", 9) == 0) {
911 if (!value || !*value) {
912 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
913 return 1; /* needs_arg; */
915 if (strnlen(value, 65) < 65) {
916 if(strnicmp(value,"default",7))
917 vol->iocharset = value;
918 /* if iocharset not set load_nls_default used by caller */
919 cFYI(1, ("iocharset set to %s",value));
920 } else {
921 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
922 return 1;
924 } else if (strnicmp(data, "uid", 3) == 0) {
925 if (value && *value) {
926 vol->linux_uid =
927 simple_strtoul(value, &value, 0);
929 } else if (strnicmp(data, "gid", 3) == 0) {
930 if (value && *value) {
931 vol->linux_gid =
932 simple_strtoul(value, &value, 0);
934 } else if (strnicmp(data, "file_mode", 4) == 0) {
935 if (value && *value) {
936 vol->file_mode =
937 simple_strtoul(value, &value, 0);
939 } else if (strnicmp(data, "dir_mode", 4) == 0) {
940 if (value && *value) {
941 vol->dir_mode =
942 simple_strtoul(value, &value, 0);
944 } else if (strnicmp(data, "dirmode", 4) == 0) {
945 if (value && *value) {
946 vol->dir_mode =
947 simple_strtoul(value, &value, 0);
949 } else if (strnicmp(data, "port", 4) == 0) {
950 if (value && *value) {
951 vol->port =
952 simple_strtoul(value, &value, 0);
954 } else if (strnicmp(data, "rsize", 5) == 0) {
955 if (value && *value) {
956 vol->rsize =
957 simple_strtoul(value, &value, 0);
959 } else if (strnicmp(data, "wsize", 5) == 0) {
960 if (value && *value) {
961 vol->wsize =
962 simple_strtoul(value, &value, 0);
964 } else if (strnicmp(data, "sockopt", 5) == 0) {
965 if (value && *value) {
966 vol->sockopt =
967 simple_strtoul(value, &value, 0);
969 } else if (strnicmp(data, "netbiosname", 4) == 0) {
970 if (!value || !*value || (*value == ' ')) {
971 cFYI(1,("invalid (empty) netbiosname specified"));
972 } else {
973 memset(vol->source_rfc1001_name,0x20,15);
974 for(i=0;i<15;i++) {
975 /* BB are there cases in which a comma can be
976 valid in this workstation netbios name (and need
977 special handling)? */
979 /* We do not uppercase netbiosname for user */
980 if (value[i]==0)
981 break;
982 else
983 vol->source_rfc1001_name[i] = value[i];
985 /* The string has 16th byte zero still from
986 set at top of the function */
987 if((i==15) && (value[i] != 0))
988 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
990 } else if (strnicmp(data, "credentials", 4) == 0) {
991 /* ignore */
992 } else if (strnicmp(data, "version", 3) == 0) {
993 /* ignore */
994 } else if (strnicmp(data, "guest",5) == 0) {
995 /* ignore */
996 } else if (strnicmp(data, "rw", 2) == 0) {
997 vol->rw = TRUE;
998 } else if ((strnicmp(data, "suid", 4) == 0) ||
999 (strnicmp(data, "nosuid", 6) == 0) ||
1000 (strnicmp(data, "exec", 4) == 0) ||
1001 (strnicmp(data, "noexec", 6) == 0) ||
1002 (strnicmp(data, "nodev", 5) == 0) ||
1003 (strnicmp(data, "noauto", 6) == 0) ||
1004 (strnicmp(data, "dev", 3) == 0)) {
1005 /* The mount tool or mount.cifs helper (if present)
1006 uses these opts to set flags, and the flags are read
1007 by the kernel vfs layer before we get here (ie
1008 before read super) so there is no point trying to
1009 parse these options again and set anything and it
1010 is ok to just ignore them */
1011 continue;
1012 } else if (strnicmp(data, "ro", 2) == 0) {
1013 vol->rw = FALSE;
1014 } else if (strnicmp(data, "hard", 4) == 0) {
1015 vol->retry = 1;
1016 } else if (strnicmp(data, "soft", 4) == 0) {
1017 vol->retry = 0;
1018 } else if (strnicmp(data, "perm", 4) == 0) {
1019 vol->noperm = 0;
1020 } else if (strnicmp(data, "noperm", 6) == 0) {
1021 vol->noperm = 1;
1022 } else if (strnicmp(data, "mapchars", 8) == 0) {
1023 vol->remap = 1;
1024 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1025 vol->remap = 0;
1026 } else if (strnicmp(data, "setuids", 7) == 0) {
1027 vol->setuids = 1;
1028 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1029 vol->setuids = 0;
1030 } else if (strnicmp(data, "nohard", 6) == 0) {
1031 vol->retry = 0;
1032 } else if (strnicmp(data, "nosoft", 6) == 0) {
1033 vol->retry = 1;
1034 } else if (strnicmp(data, "nointr", 6) == 0) {
1035 vol->intr = 0;
1036 } else if (strnicmp(data, "intr", 4) == 0) {
1037 vol->intr = 1;
1038 } else if (strnicmp(data, "serverino",7) == 0) {
1039 vol->server_ino = 1;
1040 } else if (strnicmp(data, "noserverino",9) == 0) {
1041 vol->server_ino = 0;
1042 } else if (strnicmp(data, "acl",3) == 0) {
1043 vol->no_psx_acl = 0;
1044 } else if (strnicmp(data, "noacl",5) == 0) {
1045 vol->no_psx_acl = 1;
1046 } else if (strnicmp(data, "direct",6) == 0) {
1047 vol->direct_io = 1;
1048 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1049 vol->direct_io = 1;
1050 } else if (strnicmp(data, "in6_addr",8) == 0) {
1051 if (!value || !*value) {
1052 vol->in6_addr = NULL;
1053 } else if (strnlen(value, 49) == 48) {
1054 vol->in6_addr = value;
1055 } else {
1056 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1057 return 1;
1059 } else if (strnicmp(data, "noac", 4) == 0) {
1060 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1061 } else
1062 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1064 if (vol->UNC == NULL) {
1065 if(devname == NULL) {
1066 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1067 return 1;
1069 if ((temp_len = strnlen(devname, 300)) < 300) {
1070 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1071 if(vol->UNC == NULL)
1072 return 1;
1073 strcpy(vol->UNC,devname);
1074 if (strncmp(vol->UNC, "//", 2) == 0) {
1075 vol->UNC[0] = '\\';
1076 vol->UNC[1] = '\\';
1077 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1078 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1079 return 1;
1081 } else {
1082 printk(KERN_WARNING "CIFS: UNC name too long\n");
1083 return 1;
1086 if(vol->UNCip == NULL)
1087 vol->UNCip = &vol->UNC[2];
1089 return 0;
1092 static struct cifsSesInfo *
1093 cifs_find_tcp_session(struct in_addr * target_ip_addr,
1094 struct in6_addr *target_ip6_addr,
1095 char *userName, struct TCP_Server_Info **psrvTcp)
1097 struct list_head *tmp;
1098 struct cifsSesInfo *ses;
1099 *psrvTcp = NULL;
1100 read_lock(&GlobalSMBSeslock);
1102 list_for_each(tmp, &GlobalSMBSessionList) {
1103 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1104 if (ses->server) {
1105 if((target_ip_addr &&
1106 (ses->server->addr.sockAddr.sin_addr.s_addr
1107 == target_ip_addr->s_addr)) || (target_ip6_addr
1108 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1109 target_ip6_addr,sizeof(*target_ip6_addr)))){
1110 /* BB lock server and tcp session and increment use count here?? */
1111 *psrvTcp = ses->server; /* found a match on the TCP session */
1112 /* BB check if reconnection needed */
1113 if (strncmp
1114 (ses->userName, userName,
1115 MAX_USERNAME_SIZE) == 0){
1116 read_unlock(&GlobalSMBSeslock);
1117 return ses; /* found exact match on both tcp and SMB sessions */
1121 /* else tcp and smb sessions need reconnection */
1123 read_unlock(&GlobalSMBSeslock);
1124 return NULL;
1127 static struct cifsTconInfo *
1128 find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1130 struct list_head *tmp;
1131 struct cifsTconInfo *tcon;
1133 read_lock(&GlobalSMBSeslock);
1134 list_for_each(tmp, &GlobalTreeConnectionList) {
1135 cFYI(1, ("Next tcon - "));
1136 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1137 if (tcon->ses) {
1138 if (tcon->ses->server) {
1139 cFYI(1,
1140 (" old ip addr: %x == new ip %x ?",
1141 tcon->ses->server->addr.sockAddr.sin_addr.
1142 s_addr, new_target_ip_addr));
1143 if (tcon->ses->server->addr.sockAddr.sin_addr.
1144 s_addr == new_target_ip_addr) {
1145 /* BB lock tcon and server and tcp session and increment use count here? */
1146 /* found a match on the TCP session */
1147 /* BB check if reconnection needed */
1148 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1149 tcon->treeName, uncName));
1150 if (strncmp
1151 (tcon->treeName, uncName,
1152 MAX_TREE_SIZE) == 0) {
1153 cFYI(1,
1154 ("Matched UNC, old user: %s == new: %s ?",
1155 tcon->treeName, uncName));
1156 if (strncmp
1157 (tcon->ses->userName,
1158 userName,
1159 MAX_USERNAME_SIZE) == 0) {
1160 read_unlock(&GlobalSMBSeslock);
1161 return tcon;/* also matched user (smb session)*/
1168 read_unlock(&GlobalSMBSeslock);
1169 return NULL;
1173 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1174 const char *old_path, const struct nls_table *nls_codepage,
1175 int remap)
1177 unsigned char *referrals = NULL;
1178 unsigned int num_referrals;
1179 int rc = 0;
1181 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
1182 &num_referrals, &referrals, remap);
1184 /* BB Add in code to: if valid refrl, if not ip address contact
1185 the helper that resolves tcp names, mount to it, try to
1186 tcon to it unmount it if fail */
1188 if(referrals)
1189 kfree(referrals);
1191 return rc;
1195 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1196 const char *old_path, const struct nls_table *nls_codepage,
1197 unsigned int *pnum_referrals,
1198 unsigned char ** preferrals, int remap)
1200 char *temp_unc;
1201 int rc = 0;
1203 *pnum_referrals = 0;
1205 if (pSesInfo->ipc_tid == 0) {
1206 temp_unc = kmalloc(2 /* for slashes */ +
1207 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1208 + 1 + 4 /* slash IPC$ */ + 2,
1209 GFP_KERNEL);
1210 if (temp_unc == NULL)
1211 return -ENOMEM;
1212 temp_unc[0] = '\\';
1213 temp_unc[1] = '\\';
1214 strcpy(temp_unc + 2, pSesInfo->serverName);
1215 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1216 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1217 cFYI(1,
1218 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1219 kfree(temp_unc);
1221 if (rc == 0)
1222 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
1223 pnum_referrals, nls_codepage, remap);
1225 return rc;
1228 /* See RFC1001 section 14 on representation of Netbios names */
1229 static void rfc1002mangle(char * target,char * source, unsigned int length)
1231 unsigned int i,j;
1233 for(i=0,j=0;i<(length);i++) {
1234 /* mask a nibble at a time and encode */
1235 target[j] = 'A' + (0x0F & (source[i] >> 4));
1236 target[j+1] = 'A' + (0x0F & source[i]);
1237 j+=2;
1243 static int
1244 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1245 char * netbios_name)
1247 int rc = 0;
1248 int connected = 0;
1249 __be16 orig_port = 0;
1251 if(*csocket == NULL) {
1252 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1253 if (rc < 0) {
1254 cERROR(1, ("Error %d creating socket",rc));
1255 *csocket = NULL;
1256 return rc;
1257 } else {
1258 /* BB other socket options to set KEEPALIVE, NODELAY? */
1259 cFYI(1,("Socket created"));
1260 (*csocket)->sk->sk_allocation = GFP_NOFS;
1264 psin_server->sin_family = AF_INET;
1265 if(psin_server->sin_port) { /* user overrode default port */
1266 rc = (*csocket)->ops->connect(*csocket,
1267 (struct sockaddr *) psin_server,
1268 sizeof (struct sockaddr_in),0);
1269 if (rc >= 0)
1270 connected = 1;
1273 if(!connected) {
1274 /* save original port so we can retry user specified port
1275 later if fall back ports fail this time */
1276 orig_port = psin_server->sin_port;
1278 /* do not retry on the same port we just failed on */
1279 if(psin_server->sin_port != htons(CIFS_PORT)) {
1280 psin_server->sin_port = htons(CIFS_PORT);
1282 rc = (*csocket)->ops->connect(*csocket,
1283 (struct sockaddr *) psin_server,
1284 sizeof (struct sockaddr_in),0);
1285 if (rc >= 0)
1286 connected = 1;
1289 if (!connected) {
1290 psin_server->sin_port = htons(RFC1001_PORT);
1291 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1292 psin_server, sizeof (struct sockaddr_in),0);
1293 if (rc >= 0)
1294 connected = 1;
1297 /* give up here - unless we want to retry on different
1298 protocol families some day */
1299 if (!connected) {
1300 if(orig_port)
1301 psin_server->sin_port = orig_port;
1302 cFYI(1,("Error %d connecting to server via ipv4",rc));
1303 sock_release(*csocket);
1304 *csocket = NULL;
1305 return rc;
1307 /* Eventually check for other socket options to change from
1308 the default. sock_setsockopt not used because it expects
1309 user space buffer */
1310 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1312 /* send RFC1001 sessinit */
1314 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1315 /* some servers require RFC1001 sessinit before sending
1316 negprot - BB check reconnection in case where second
1317 sessinit is sent but no second negprot */
1318 struct rfc1002_session_packet * ses_init_buf;
1319 struct smb_hdr * smb_buf;
1320 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
1321 if(ses_init_buf) {
1322 ses_init_buf->trailer.session_req.called_len = 32;
1323 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1324 DEFAULT_CIFS_CALLED_NAME,16);
1325 ses_init_buf->trailer.session_req.calling_len = 32;
1326 /* calling name ends in null (byte 16) from old smb
1327 convention. */
1328 if(netbios_name && (netbios_name[0] !=0)) {
1329 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1330 netbios_name,16);
1331 } else {
1332 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1333 "LINUX_CIFS_CLNT",16);
1335 ses_init_buf->trailer.session_req.scope1 = 0;
1336 ses_init_buf->trailer.session_req.scope2 = 0;
1337 smb_buf = (struct smb_hdr *)ses_init_buf;
1338 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1339 smb_buf->smb_buf_length = 0x81000044;
1340 rc = smb_send(*csocket, smb_buf, 0x44,
1341 (struct sockaddr *)psin_server);
1342 kfree(ses_init_buf);
1344 /* else the negprot may still work without this
1345 even though malloc failed */
1349 return rc;
1352 static int
1353 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1355 int rc = 0;
1356 int connected = 0;
1357 __be16 orig_port = 0;
1359 if(*csocket == NULL) {
1360 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1361 if (rc < 0) {
1362 cERROR(1, ("Error %d creating ipv6 socket",rc));
1363 *csocket = NULL;
1364 return rc;
1365 } else {
1366 /* BB other socket options to set KEEPALIVE, NODELAY? */
1367 cFYI(1,("ipv6 Socket created"));
1368 (*csocket)->sk->sk_allocation = GFP_NOFS;
1372 psin_server->sin6_family = AF_INET6;
1374 if(psin_server->sin6_port) { /* user overrode default port */
1375 rc = (*csocket)->ops->connect(*csocket,
1376 (struct sockaddr *) psin_server,
1377 sizeof (struct sockaddr_in6),0);
1378 if (rc >= 0)
1379 connected = 1;
1382 if(!connected) {
1383 /* save original port so we can retry user specified port
1384 later if fall back ports fail this time */
1386 orig_port = psin_server->sin6_port;
1387 /* do not retry on the same port we just failed on */
1388 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1389 psin_server->sin6_port = htons(CIFS_PORT);
1391 rc = (*csocket)->ops->connect(*csocket,
1392 (struct sockaddr *) psin_server,
1393 sizeof (struct sockaddr_in6),0);
1394 if (rc >= 0)
1395 connected = 1;
1398 if (!connected) {
1399 psin_server->sin6_port = htons(RFC1001_PORT);
1400 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1401 psin_server, sizeof (struct sockaddr_in6),0);
1402 if (rc >= 0)
1403 connected = 1;
1406 /* give up here - unless we want to retry on different
1407 protocol families some day */
1408 if (!connected) {
1409 if(orig_port)
1410 psin_server->sin6_port = orig_port;
1411 cFYI(1,("Error %d connecting to server via ipv6",rc));
1412 sock_release(*csocket);
1413 *csocket = NULL;
1414 return rc;
1416 /* Eventually check for other socket options to change from
1417 the default. sock_setsockopt not used because it expects
1418 user space buffer */
1419 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1421 return rc;
1425 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1426 char *mount_data, const char *devname)
1428 int rc = 0;
1429 int xid;
1430 int address_type = AF_INET;
1431 struct socket *csocket = NULL;
1432 struct sockaddr_in sin_server;
1433 struct sockaddr_in6 sin_server6;
1434 struct smb_vol volume_info;
1435 struct cifsSesInfo *pSesInfo = NULL;
1436 struct cifsSesInfo *existingCifsSes = NULL;
1437 struct cifsTconInfo *tcon = NULL;
1438 struct TCP_Server_Info *srvTcp = NULL;
1440 xid = GetXid();
1442 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1444 memset(&volume_info,0,sizeof(struct smb_vol));
1445 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1446 if(volume_info.UNC)
1447 kfree(volume_info.UNC);
1448 if(volume_info.password)
1449 kfree(volume_info.password);
1450 FreeXid(xid);
1451 return -EINVAL;
1454 if (volume_info.username) {
1455 /* BB fixme parse for domain name here */
1456 cFYI(1, ("Username: %s ", volume_info.username));
1458 } else {
1459 cifserror("No username specified ");
1460 /* In userspace mount helper we can get user name from alternate
1461 locations such as env variables and files on disk */
1462 if(volume_info.UNC)
1463 kfree(volume_info.UNC);
1464 if(volume_info.password)
1465 kfree(volume_info.password);
1466 FreeXid(xid);
1467 return -EINVAL;
1470 if (volume_info.UNCip && volume_info.UNC) {
1471 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1473 if(rc <= 0) {
1474 /* not ipv4 address, try ipv6 */
1475 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1476 if(rc > 0)
1477 address_type = AF_INET6;
1478 } else {
1479 address_type = AF_INET;
1482 if(rc <= 0) {
1483 /* we failed translating address */
1484 if(volume_info.UNC)
1485 kfree(volume_info.UNC);
1486 if(volume_info.password)
1487 kfree(volume_info.password);
1488 FreeXid(xid);
1489 return -EINVAL;
1492 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1493 /* success */
1494 rc = 0;
1495 } else if (volume_info.UNCip){
1496 /* BB using ip addr as server name connect to the DFS root below */
1497 cERROR(1,("Connecting to DFS root not implemented yet"));
1498 if(volume_info.UNC)
1499 kfree(volume_info.UNC);
1500 if(volume_info.password)
1501 kfree(volume_info.password);
1502 FreeXid(xid);
1503 return -EINVAL;
1504 } else /* which servers DFS root would we conect to */ {
1505 cERROR(1,
1506 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1507 if(volume_info.UNC)
1508 kfree(volume_info.UNC);
1509 if(volume_info.password)
1510 kfree(volume_info.password);
1511 FreeXid(xid);
1512 return -EINVAL;
1515 /* this is needed for ASCII cp to Unicode converts */
1516 if(volume_info.iocharset == NULL) {
1517 cifs_sb->local_nls = load_nls_default();
1518 /* load_nls_default can not return null */
1519 } else {
1520 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1521 if(cifs_sb->local_nls == NULL) {
1522 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1523 if(volume_info.UNC)
1524 kfree(volume_info.UNC);
1525 if(volume_info.password)
1526 kfree(volume_info.password);
1527 FreeXid(xid);
1528 return -ELIBACC;
1532 if(address_type == AF_INET)
1533 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1534 NULL /* no ipv6 addr */,
1535 volume_info.username, &srvTcp);
1536 else if(address_type == AF_INET6)
1537 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1538 &sin_server6.sin6_addr,
1539 volume_info.username, &srvTcp);
1540 else {
1541 if(volume_info.UNC)
1542 kfree(volume_info.UNC);
1543 if(volume_info.password)
1544 kfree(volume_info.password);
1545 FreeXid(xid);
1546 return -EINVAL;
1550 if (srvTcp) {
1551 cFYI(1, ("Existing tcp session with server found "));
1552 } else { /* create socket */
1553 if(volume_info.port)
1554 sin_server.sin_port = htons(volume_info.port);
1555 else
1556 sin_server.sin_port = 0;
1557 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1558 if (rc < 0) {
1559 cERROR(1,
1560 ("Error connecting to IPv4 socket. Aborting operation"));
1561 if(csocket != NULL)
1562 sock_release(csocket);
1563 if(volume_info.UNC)
1564 kfree(volume_info.UNC);
1565 if(volume_info.password)
1566 kfree(volume_info.password);
1567 FreeXid(xid);
1568 return rc;
1571 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1572 if (srvTcp == NULL) {
1573 rc = -ENOMEM;
1574 sock_release(csocket);
1575 if(volume_info.UNC)
1576 kfree(volume_info.UNC);
1577 if(volume_info.password)
1578 kfree(volume_info.password);
1579 FreeXid(xid);
1580 return rc;
1581 } else {
1582 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1583 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1584 atomic_set(&srvTcp->inFlight,0);
1585 /* BB Add code for ipv6 case too */
1586 srvTcp->ssocket = csocket;
1587 srvTcp->protocolType = IPV4;
1588 init_waitqueue_head(&srvTcp->response_q);
1589 init_waitqueue_head(&srvTcp->request_q);
1590 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1591 /* at this point we are the only ones with the pointer
1592 to the struct since the kernel thread not created yet
1593 so no need to spinlock this init of tcpStatus */
1594 srvTcp->tcpStatus = CifsNew;
1595 init_MUTEX(&srvTcp->tcpSem);
1596 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1597 CLONE_FS | CLONE_FILES | CLONE_VM);
1598 if(rc < 0) {
1599 rc = -ENOMEM;
1600 sock_release(csocket);
1601 if(volume_info.UNC)
1602 kfree(volume_info.UNC);
1603 if(volume_info.password)
1604 kfree(volume_info.password);
1605 FreeXid(xid);
1606 return rc;
1607 } else
1608 rc = 0;
1609 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1610 srvTcp->sequence_number = 0;
1614 if (existingCifsSes) {
1615 pSesInfo = existingCifsSes;
1616 cFYI(1, ("Existing smb sess found "));
1617 if(volume_info.password)
1618 kfree(volume_info.password);
1619 /* volume_info.UNC freed at end of function */
1620 } else if (!rc) {
1621 cFYI(1, ("Existing smb sess not found "));
1622 pSesInfo = sesInfoAlloc();
1623 if (pSesInfo == NULL)
1624 rc = -ENOMEM;
1625 else {
1626 pSesInfo->server = srvTcp;
1627 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1628 NIPQUAD(sin_server.sin_addr.s_addr));
1631 if (!rc){
1632 /* volume_info.password freed at unmount */
1633 if (volume_info.password)
1634 pSesInfo->password = volume_info.password;
1635 if (volume_info.username)
1636 strncpy(pSesInfo->userName,
1637 volume_info.username,MAX_USERNAME_SIZE);
1638 if (volume_info.domainname)
1639 strncpy(pSesInfo->domainName,
1640 volume_info.domainname,MAX_USERNAME_SIZE);
1641 pSesInfo->linux_uid = volume_info.linux_uid;
1642 down(&pSesInfo->sesSem);
1643 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1644 up(&pSesInfo->sesSem);
1645 if(!rc)
1646 atomic_inc(&srvTcp->socketUseCount);
1647 } else
1648 if(volume_info.password)
1649 kfree(volume_info.password);
1652 /* search for existing tcon to this server share */
1653 if (!rc) {
1654 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1655 cifs_sb->rsize = volume_info.rsize;
1656 else
1657 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1658 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1659 cifs_sb->wsize = volume_info.wsize;
1660 else
1661 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1662 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1663 cifs_sb->rsize = PAGE_CACHE_SIZE;
1664 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1666 cifs_sb->mnt_uid = volume_info.linux_uid;
1667 cifs_sb->mnt_gid = volume_info.linux_gid;
1668 cifs_sb->mnt_file_mode = volume_info.file_mode;
1669 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1670 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1672 if(volume_info.noperm)
1673 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1674 if(volume_info.setuids)
1675 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1676 if(volume_info.server_ino)
1677 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1678 if(volume_info.remap)
1679 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1680 if(volume_info.no_xattr)
1681 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1682 if(volume_info.direct_io) {
1683 cERROR(1,("mounting share using direct i/o"));
1684 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1687 tcon =
1688 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1689 volume_info.username);
1690 if (tcon) {
1691 cFYI(1, ("Found match on UNC path "));
1692 /* we can have only one retry value for a connection
1693 to a share so for resources mounted more than once
1694 to the same server share the last value passed in
1695 for the retry flag is used */
1696 tcon->retry = volume_info.retry;
1697 } else {
1698 tcon = tconInfoAlloc();
1699 if (tcon == NULL)
1700 rc = -ENOMEM;
1701 else {
1702 /* check for null share name ie connect to dfs root */
1704 /* BB check if this works for exactly length three strings */
1705 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1706 && (strchr(volume_info.UNC + 3, '/') ==
1707 NULL)) {
1708 rc = connect_to_dfs_path(xid, pSesInfo,
1709 "", cifs_sb->local_nls,
1710 cifs_sb->mnt_cifs_flags &
1711 CIFS_MOUNT_MAP_SPECIAL_CHR);
1712 if(volume_info.UNC)
1713 kfree(volume_info.UNC);
1714 FreeXid(xid);
1715 return -ENODEV;
1716 } else {
1717 rc = CIFSTCon(xid, pSesInfo,
1718 volume_info.UNC,
1719 tcon, cifs_sb->local_nls);
1720 cFYI(1, ("CIFS Tcon rc = %d", rc));
1722 if (!rc) {
1723 atomic_inc(&pSesInfo->inUse);
1724 tcon->retry = volume_info.retry;
1729 if(pSesInfo) {
1730 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1731 sb->s_maxbytes = (u64) 1 << 63;
1732 } else
1733 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1736 sb->s_time_gran = 100;
1738 /* on error free sesinfo and tcon struct if needed */
1739 if (rc) {
1740 /* if session setup failed, use count is zero but
1741 we still need to free cifsd thread */
1742 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1743 spin_lock(&GlobalMid_Lock);
1744 srvTcp->tcpStatus = CifsExiting;
1745 spin_unlock(&GlobalMid_Lock);
1746 if(srvTcp->tsk)
1747 send_sig(SIGKILL,srvTcp->tsk,1);
1749 /* If find_unc succeeded then rc == 0 so we can not end */
1750 if (tcon) /* up accidently freeing someone elses tcon struct */
1751 tconInfoFree(tcon);
1752 if (existingCifsSes == NULL) {
1753 if (pSesInfo) {
1754 if ((pSesInfo->server) &&
1755 (pSesInfo->status == CifsGood)) {
1756 int temp_rc;
1757 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1758 /* if the socketUseCount is now zero */
1759 if((temp_rc == -ESHUTDOWN) &&
1760 (pSesInfo->server->tsk))
1761 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1762 } else
1763 cFYI(1, ("No session or bad tcon"));
1764 sesInfoFree(pSesInfo);
1765 /* pSesInfo = NULL; */
1768 } else {
1769 atomic_inc(&tcon->useCount);
1770 cifs_sb->tcon = tcon;
1771 tcon->ses = pSesInfo;
1773 /* do not care if following two calls succeed - informational only */
1774 CIFSSMBQFSDeviceInfo(xid, tcon);
1775 CIFSSMBQFSAttributeInfo(xid, tcon);
1776 if (tcon->ses->capabilities & CAP_UNIX) {
1777 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
1778 if(!volume_info.no_psx_acl) {
1779 if(CIFS_UNIX_POSIX_ACL_CAP &
1780 le64_to_cpu(tcon->fsUnixInfo.Capability))
1781 cFYI(1,("server negotiated posix acl support"));
1782 sb->s_flags |= MS_POSIXACL;
1788 /* volume_info.password is freed above when existing session found
1789 (in which case it is not needed anymore) but when new sesion is created
1790 the password ptr is put in the new session structure (in which case the
1791 password will be freed at unmount time) */
1792 if(volume_info.UNC)
1793 kfree(volume_info.UNC);
1794 FreeXid(xid);
1795 return rc;
1798 static int
1799 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1800 char session_key[CIFS_SESSION_KEY_SIZE],
1801 const struct nls_table *nls_codepage)
1803 struct smb_hdr *smb_buffer;
1804 struct smb_hdr *smb_buffer_response;
1805 SESSION_SETUP_ANDX *pSMB;
1806 SESSION_SETUP_ANDX *pSMBr;
1807 char *bcc_ptr;
1808 char *user;
1809 char *domain;
1810 int rc = 0;
1811 int remaining_words = 0;
1812 int bytes_returned = 0;
1813 int len;
1814 __u32 capabilities;
1815 __u16 count;
1817 cFYI(1, ("In sesssetup "));
1818 if(ses == NULL)
1819 return -EINVAL;
1820 user = ses->userName;
1821 domain = ses->domainName;
1822 smb_buffer = cifs_buf_get();
1823 if (smb_buffer == NULL) {
1824 return -ENOMEM;
1826 smb_buffer_response = smb_buffer;
1827 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1829 /* send SMBsessionSetup here */
1830 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1831 NULL /* no tCon exists yet */ , 13 /* wct */ );
1833 pSMB->req_no_secext.AndXCommand = 0xFF;
1834 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1835 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1837 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1838 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1840 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1841 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1842 if (ses->capabilities & CAP_UNICODE) {
1843 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1844 capabilities |= CAP_UNICODE;
1846 if (ses->capabilities & CAP_STATUS32) {
1847 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1848 capabilities |= CAP_STATUS32;
1850 if (ses->capabilities & CAP_DFS) {
1851 smb_buffer->Flags2 |= SMBFLG2_DFS;
1852 capabilities |= CAP_DFS;
1854 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1856 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1857 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1859 pSMB->req_no_secext.CaseSensitivePasswordLength =
1860 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1861 bcc_ptr = pByteArea(smb_buffer);
1862 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1863 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1864 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1865 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1867 if (ses->capabilities & CAP_UNICODE) {
1868 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1869 *bcc_ptr = 0;
1870 bcc_ptr++;
1872 if(user == NULL)
1873 bytes_returned = 0; /* skill null user */
1874 else
1875 bytes_returned =
1876 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1877 nls_codepage);
1878 /* convert number of 16 bit words to bytes */
1879 bcc_ptr += 2 * bytes_returned;
1880 bcc_ptr += 2; /* trailing null */
1881 if (domain == NULL)
1882 bytes_returned =
1883 cifs_strtoUCS((wchar_t *) bcc_ptr,
1884 "CIFS_LINUX_DOM", 32, nls_codepage);
1885 else
1886 bytes_returned =
1887 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1888 nls_codepage);
1889 bcc_ptr += 2 * bytes_returned;
1890 bcc_ptr += 2;
1891 bytes_returned =
1892 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1893 32, nls_codepage);
1894 bcc_ptr += 2 * bytes_returned;
1895 bytes_returned =
1896 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1897 32, nls_codepage);
1898 bcc_ptr += 2 * bytes_returned;
1899 bcc_ptr += 2;
1900 bytes_returned =
1901 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1902 64, nls_codepage);
1903 bcc_ptr += 2 * bytes_returned;
1904 bcc_ptr += 2;
1905 } else {
1906 if(user != NULL) {
1907 strncpy(bcc_ptr, user, 200);
1908 bcc_ptr += strnlen(user, 200);
1910 *bcc_ptr = 0;
1911 bcc_ptr++;
1912 if (domain == NULL) {
1913 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1914 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1915 } else {
1916 strncpy(bcc_ptr, domain, 64);
1917 bcc_ptr += strnlen(domain, 64);
1918 *bcc_ptr = 0;
1919 bcc_ptr++;
1921 strcpy(bcc_ptr, "Linux version ");
1922 bcc_ptr += strlen("Linux version ");
1923 strcpy(bcc_ptr, system_utsname.release);
1924 bcc_ptr += strlen(system_utsname.release) + 1;
1925 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1926 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1928 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1929 smb_buffer->smb_buf_length += count;
1930 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1932 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1933 &bytes_returned, 1);
1934 if (rc) {
1935 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1936 } else if ((smb_buffer_response->WordCount == 3)
1937 || (smb_buffer_response->WordCount == 4)) {
1938 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1939 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1940 if (action & GUEST_LOGIN)
1941 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1942 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1943 cFYI(1, ("UID = %d ", ses->Suid));
1944 /* response can have either 3 or 4 word count - Samba sends 3 */
1945 bcc_ptr = pByteArea(smb_buffer_response);
1946 if ((pSMBr->resp.hdr.WordCount == 3)
1947 || ((pSMBr->resp.hdr.WordCount == 4)
1948 && (blob_len < pSMBr->resp.ByteCount))) {
1949 if (pSMBr->resp.hdr.WordCount == 4)
1950 bcc_ptr += blob_len;
1952 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1953 if ((long) (bcc_ptr) % 2) {
1954 remaining_words =
1955 (BCC(smb_buffer_response) - 1) /2;
1956 bcc_ptr++; /* Unicode strings must be word aligned */
1957 } else {
1958 remaining_words =
1959 BCC(smb_buffer_response) / 2;
1961 len =
1962 UniStrnlen((wchar_t *) bcc_ptr,
1963 remaining_words - 1);
1964 /* We look for obvious messed up bcc or strings in response so we do not go off
1965 the end since (at least) WIN2K and Windows XP have a major bug in not null
1966 terminating last Unicode string in response */
1967 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
1968 if(ses->serverOS == NULL)
1969 goto sesssetup_nomem;
1970 cifs_strfromUCS_le(ses->serverOS,
1971 (wchar_t *)bcc_ptr, len,nls_codepage);
1972 bcc_ptr += 2 * (len + 1);
1973 remaining_words -= len + 1;
1974 ses->serverOS[2 * len] = 0;
1975 ses->serverOS[1 + (2 * len)] = 0;
1976 if (remaining_words > 0) {
1977 len = UniStrnlen((wchar_t *)bcc_ptr,
1978 remaining_words-1);
1979 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
1980 if(ses->serverNOS == NULL)
1981 goto sesssetup_nomem;
1982 cifs_strfromUCS_le(ses->serverNOS,
1983 (wchar_t *)bcc_ptr,len,nls_codepage);
1984 bcc_ptr += 2 * (len + 1);
1985 ses->serverNOS[2 * len] = 0;
1986 ses->serverNOS[1 + (2 * len)] = 0;
1987 if(strncmp(ses->serverNOS,
1988 "NT LAN Manager 4",16) == 0) {
1989 cFYI(1,("NT4 server"));
1990 ses->flags |= CIFS_SES_NT4;
1992 remaining_words -= len + 1;
1993 if (remaining_words > 0) {
1994 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
1995 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1996 ses->serverDomain =
1997 kcalloc(1, 2*(len+1),GFP_KERNEL);
1998 if(ses->serverDomain == NULL)
1999 goto sesssetup_nomem;
2000 cifs_strfromUCS_le(ses->serverDomain,
2001 (wchar_t *)bcc_ptr,len,nls_codepage);
2002 bcc_ptr += 2 * (len + 1);
2003 ses->serverDomain[2*len] = 0;
2004 ses->serverDomain[1+(2*len)] = 0;
2005 } /* else no more room so create dummy domain string */
2006 else
2007 ses->serverDomain =
2008 kcalloc(1, 2, GFP_KERNEL);
2009 } else { /* no room so create dummy domain and NOS string */
2010 /* if these kcallocs fail not much we
2011 can do, but better to not fail the
2012 sesssetup itself */
2013 ses->serverDomain =
2014 kcalloc(1, 2, GFP_KERNEL);
2015 ses->serverNOS =
2016 kcalloc(1, 2, GFP_KERNEL);
2018 } else { /* ASCII */
2019 len = strnlen(bcc_ptr, 1024);
2020 if (((long) bcc_ptr + len) - (long)
2021 pByteArea(smb_buffer_response)
2022 <= BCC(smb_buffer_response)) {
2023 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2024 if(ses->serverOS == NULL)
2025 goto sesssetup_nomem;
2026 strncpy(ses->serverOS,bcc_ptr, len);
2028 bcc_ptr += len;
2029 bcc_ptr[0] = 0; /* null terminate the string */
2030 bcc_ptr++;
2032 len = strnlen(bcc_ptr, 1024);
2033 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2034 if(ses->serverNOS == NULL)
2035 goto sesssetup_nomem;
2036 strncpy(ses->serverNOS, bcc_ptr, len);
2037 bcc_ptr += len;
2038 bcc_ptr[0] = 0;
2039 bcc_ptr++;
2041 len = strnlen(bcc_ptr, 1024);
2042 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2043 if(ses->serverDomain == NULL)
2044 goto sesssetup_nomem;
2045 strncpy(ses->serverDomain, bcc_ptr, len);
2046 bcc_ptr += len;
2047 bcc_ptr[0] = 0;
2048 bcc_ptr++;
2049 } else
2050 cFYI(1,
2051 ("Variable field of length %d extends beyond end of smb ",
2052 len));
2054 } else {
2055 cERROR(1,
2056 (" Security Blob Length extends beyond end of SMB"));
2058 } else {
2059 cERROR(1,
2060 (" Invalid Word count %d: ",
2061 smb_buffer_response->WordCount));
2062 rc = -EIO;
2064 sesssetup_nomem: /* do not return an error on nomem for the info strings,
2065 since that could make reconnection harder, and
2066 reconnection might be needed to free memory */
2067 if (smb_buffer)
2068 cifs_buf_release(smb_buffer);
2070 return rc;
2073 static int
2074 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2075 char *SecurityBlob,int SecurityBlobLength,
2076 const struct nls_table *nls_codepage)
2078 struct smb_hdr *smb_buffer;
2079 struct smb_hdr *smb_buffer_response;
2080 SESSION_SETUP_ANDX *pSMB;
2081 SESSION_SETUP_ANDX *pSMBr;
2082 char *bcc_ptr;
2083 char *user;
2084 char *domain;
2085 int rc = 0;
2086 int remaining_words = 0;
2087 int bytes_returned = 0;
2088 int len;
2089 __u32 capabilities;
2090 __u16 count;
2092 cFYI(1, ("In spnego sesssetup "));
2093 if(ses == NULL)
2094 return -EINVAL;
2095 user = ses->userName;
2096 domain = ses->domainName;
2098 smb_buffer = cifs_buf_get();
2099 if (smb_buffer == NULL) {
2100 return -ENOMEM;
2102 smb_buffer_response = smb_buffer;
2103 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2105 /* send SMBsessionSetup here */
2106 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2107 NULL /* no tCon exists yet */ , 12 /* wct */ );
2108 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2109 pSMB->req.AndXCommand = 0xFF;
2110 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2111 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2113 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2114 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2116 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2117 CAP_EXTENDED_SECURITY;
2118 if (ses->capabilities & CAP_UNICODE) {
2119 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2120 capabilities |= CAP_UNICODE;
2122 if (ses->capabilities & CAP_STATUS32) {
2123 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2124 capabilities |= CAP_STATUS32;
2126 if (ses->capabilities & CAP_DFS) {
2127 smb_buffer->Flags2 |= SMBFLG2_DFS;
2128 capabilities |= CAP_DFS;
2130 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2132 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2133 bcc_ptr = pByteArea(smb_buffer);
2134 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2135 bcc_ptr += SecurityBlobLength;
2137 if (ses->capabilities & CAP_UNICODE) {
2138 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2139 *bcc_ptr = 0;
2140 bcc_ptr++;
2142 bytes_returned =
2143 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2144 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2145 bcc_ptr += 2; /* trailing null */
2146 if (domain == NULL)
2147 bytes_returned =
2148 cifs_strtoUCS((wchar_t *) bcc_ptr,
2149 "CIFS_LINUX_DOM", 32, nls_codepage);
2150 else
2151 bytes_returned =
2152 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2153 nls_codepage);
2154 bcc_ptr += 2 * bytes_returned;
2155 bcc_ptr += 2;
2156 bytes_returned =
2157 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2158 32, nls_codepage);
2159 bcc_ptr += 2 * bytes_returned;
2160 bytes_returned =
2161 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2162 nls_codepage);
2163 bcc_ptr += 2 * bytes_returned;
2164 bcc_ptr += 2;
2165 bytes_returned =
2166 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2167 64, nls_codepage);
2168 bcc_ptr += 2 * bytes_returned;
2169 bcc_ptr += 2;
2170 } else {
2171 strncpy(bcc_ptr, user, 200);
2172 bcc_ptr += strnlen(user, 200);
2173 *bcc_ptr = 0;
2174 bcc_ptr++;
2175 if (domain == NULL) {
2176 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2177 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2178 } else {
2179 strncpy(bcc_ptr, domain, 64);
2180 bcc_ptr += strnlen(domain, 64);
2181 *bcc_ptr = 0;
2182 bcc_ptr++;
2184 strcpy(bcc_ptr, "Linux version ");
2185 bcc_ptr += strlen("Linux version ");
2186 strcpy(bcc_ptr, system_utsname.release);
2187 bcc_ptr += strlen(system_utsname.release) + 1;
2188 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2189 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2191 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2192 smb_buffer->smb_buf_length += count;
2193 pSMB->req.ByteCount = cpu_to_le16(count);
2195 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2196 &bytes_returned, 1);
2197 if (rc) {
2198 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2199 } else if ((smb_buffer_response->WordCount == 3)
2200 || (smb_buffer_response->WordCount == 4)) {
2201 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2202 __u16 blob_len =
2203 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2204 if (action & GUEST_LOGIN)
2205 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2206 if (ses) {
2207 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2208 cFYI(1, ("UID = %d ", ses->Suid));
2209 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2211 /* BB Fix below to make endian neutral !! */
2213 if ((pSMBr->resp.hdr.WordCount == 3)
2214 || ((pSMBr->resp.hdr.WordCount == 4)
2215 && (blob_len <
2216 pSMBr->resp.ByteCount))) {
2217 if (pSMBr->resp.hdr.WordCount == 4) {
2218 bcc_ptr +=
2219 blob_len;
2220 cFYI(1,
2221 ("Security Blob Length %d ",
2222 blob_len));
2225 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2226 if ((long) (bcc_ptr) % 2) {
2227 remaining_words =
2228 (BCC(smb_buffer_response)
2229 - 1) / 2;
2230 bcc_ptr++; /* Unicode strings must be word aligned */
2231 } else {
2232 remaining_words =
2234 (smb_buffer_response) / 2;
2236 len =
2237 UniStrnlen((wchar_t *) bcc_ptr,
2238 remaining_words - 1);
2239 /* We look for obvious messed up bcc or strings in response so we do not go off
2240 the end since (at least) WIN2K and Windows XP have a major bug in not null
2241 terminating last Unicode string in response */
2242 ses->serverOS =
2243 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2244 cifs_strfromUCS_le(ses->serverOS,
2245 (wchar_t *)
2246 bcc_ptr, len,
2247 nls_codepage);
2248 bcc_ptr += 2 * (len + 1);
2249 remaining_words -= len + 1;
2250 ses->serverOS[2 * len] = 0;
2251 ses->serverOS[1 + (2 * len)] = 0;
2252 if (remaining_words > 0) {
2253 len = UniStrnlen((wchar_t *)bcc_ptr,
2254 remaining_words
2255 - 1);
2256 ses->serverNOS =
2257 kcalloc(1, 2 * (len + 1),
2258 GFP_KERNEL);
2259 cifs_strfromUCS_le(ses->serverNOS,
2260 (wchar_t *)bcc_ptr,
2261 len,
2262 nls_codepage);
2263 bcc_ptr += 2 * (len + 1);
2264 ses->serverNOS[2 * len] = 0;
2265 ses->serverNOS[1 + (2 * len)] = 0;
2266 remaining_words -= len + 1;
2267 if (remaining_words > 0) {
2268 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2269 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2270 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
2271 cifs_strfromUCS_le(ses->serverDomain,
2272 (wchar_t *)bcc_ptr,
2273 len,
2274 nls_codepage);
2275 bcc_ptr += 2*(len+1);
2276 ses->serverDomain[2*len] = 0;
2277 ses->serverDomain[1+(2*len)] = 0;
2278 } /* else no more room so create dummy domain string */
2279 else
2280 ses->serverDomain =
2281 kcalloc(1, 2,GFP_KERNEL);
2282 } else { /* no room so create dummy domain and NOS string */
2283 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2284 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
2286 } else { /* ASCII */
2288 len = strnlen(bcc_ptr, 1024);
2289 if (((long) bcc_ptr + len) - (long)
2290 pByteArea(smb_buffer_response)
2291 <= BCC(smb_buffer_response)) {
2292 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
2293 strncpy(ses->serverOS, bcc_ptr, len);
2295 bcc_ptr += len;
2296 bcc_ptr[0] = 0; /* null terminate the string */
2297 bcc_ptr++;
2299 len = strnlen(bcc_ptr, 1024);
2300 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2301 strncpy(ses->serverNOS, bcc_ptr, len);
2302 bcc_ptr += len;
2303 bcc_ptr[0] = 0;
2304 bcc_ptr++;
2306 len = strnlen(bcc_ptr, 1024);
2307 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
2308 strncpy(ses->serverDomain, bcc_ptr, len);
2309 bcc_ptr += len;
2310 bcc_ptr[0] = 0;
2311 bcc_ptr++;
2312 } else
2313 cFYI(1,
2314 ("Variable field of length %d extends beyond end of smb ",
2315 len));
2317 } else {
2318 cERROR(1,
2319 (" Security Blob Length extends beyond end of SMB"));
2321 } else {
2322 cERROR(1, ("No session structure passed in."));
2324 } else {
2325 cERROR(1,
2326 (" Invalid Word count %d: ",
2327 smb_buffer_response->WordCount));
2328 rc = -EIO;
2331 if (smb_buffer)
2332 cifs_buf_release(smb_buffer);
2334 return rc;
2337 static int
2338 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2339 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2340 const struct nls_table *nls_codepage)
2342 struct smb_hdr *smb_buffer;
2343 struct smb_hdr *smb_buffer_response;
2344 SESSION_SETUP_ANDX *pSMB;
2345 SESSION_SETUP_ANDX *pSMBr;
2346 char *bcc_ptr;
2347 char *domain;
2348 int rc = 0;
2349 int remaining_words = 0;
2350 int bytes_returned = 0;
2351 int len;
2352 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2353 PNEGOTIATE_MESSAGE SecurityBlob;
2354 PCHALLENGE_MESSAGE SecurityBlob2;
2355 __u32 negotiate_flags, capabilities;
2356 __u16 count;
2358 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2359 if(ses == NULL)
2360 return -EINVAL;
2361 domain = ses->domainName;
2362 *pNTLMv2_flag = FALSE;
2363 smb_buffer = cifs_buf_get();
2364 if (smb_buffer == NULL) {
2365 return -ENOMEM;
2367 smb_buffer_response = smb_buffer;
2368 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2369 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2371 /* send SMBsessionSetup here */
2372 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2373 NULL /* no tCon exists yet */ , 12 /* wct */ );
2374 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2375 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2377 pSMB->req.AndXCommand = 0xFF;
2378 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2379 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2381 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2382 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2384 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2385 CAP_EXTENDED_SECURITY;
2386 if (ses->capabilities & CAP_UNICODE) {
2387 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2388 capabilities |= CAP_UNICODE;
2390 if (ses->capabilities & CAP_STATUS32) {
2391 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2392 capabilities |= CAP_STATUS32;
2394 if (ses->capabilities & CAP_DFS) {
2395 smb_buffer->Flags2 |= SMBFLG2_DFS;
2396 capabilities |= CAP_DFS;
2398 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2400 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2401 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2402 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2403 SecurityBlob->MessageType = NtLmNegotiate;
2404 negotiate_flags =
2405 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2406 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2407 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2408 if(sign_CIFS_PDUs)
2409 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2410 if(ntlmv2_support)
2411 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2412 /* setup pointers to domain name and workstation name */
2413 bcc_ptr += SecurityBlobLength;
2415 SecurityBlob->WorkstationName.Buffer = 0;
2416 SecurityBlob->WorkstationName.Length = 0;
2417 SecurityBlob->WorkstationName.MaximumLength = 0;
2419 if (domain == NULL) {
2420 SecurityBlob->DomainName.Buffer = 0;
2421 SecurityBlob->DomainName.Length = 0;
2422 SecurityBlob->DomainName.MaximumLength = 0;
2423 } else {
2424 __u16 len;
2425 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2426 strncpy(bcc_ptr, domain, 63);
2427 len = strnlen(domain, 64);
2428 SecurityBlob->DomainName.MaximumLength =
2429 cpu_to_le16(len);
2430 SecurityBlob->DomainName.Buffer =
2431 cpu_to_le32((long) &SecurityBlob->
2432 DomainString -
2433 (long) &SecurityBlob->Signature);
2434 bcc_ptr += len;
2435 SecurityBlobLength += len;
2436 SecurityBlob->DomainName.Length =
2437 cpu_to_le16(len);
2439 if (ses->capabilities & CAP_UNICODE) {
2440 if ((long) bcc_ptr % 2) {
2441 *bcc_ptr = 0;
2442 bcc_ptr++;
2445 bytes_returned =
2446 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2447 32, nls_codepage);
2448 bcc_ptr += 2 * bytes_returned;
2449 bytes_returned =
2450 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2451 nls_codepage);
2452 bcc_ptr += 2 * bytes_returned;
2453 bcc_ptr += 2; /* null terminate Linux version */
2454 bytes_returned =
2455 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2456 64, nls_codepage);
2457 bcc_ptr += 2 * bytes_returned;
2458 *(bcc_ptr + 1) = 0;
2459 *(bcc_ptr + 2) = 0;
2460 bcc_ptr += 2; /* null terminate network opsys string */
2461 *(bcc_ptr + 1) = 0;
2462 *(bcc_ptr + 2) = 0;
2463 bcc_ptr += 2; /* null domain */
2464 } else { /* ASCII */
2465 strcpy(bcc_ptr, "Linux version ");
2466 bcc_ptr += strlen("Linux version ");
2467 strcpy(bcc_ptr, system_utsname.release);
2468 bcc_ptr += strlen(system_utsname.release) + 1;
2469 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2470 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2471 bcc_ptr++; /* empty domain field */
2472 *bcc_ptr = 0;
2474 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2475 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2476 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2477 smb_buffer->smb_buf_length += count;
2478 pSMB->req.ByteCount = cpu_to_le16(count);
2480 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2481 &bytes_returned, 1);
2483 if (smb_buffer_response->Status.CifsError ==
2484 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2485 rc = 0;
2487 if (rc) {
2488 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2489 } else if ((smb_buffer_response->WordCount == 3)
2490 || (smb_buffer_response->WordCount == 4)) {
2491 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2492 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2494 if (action & GUEST_LOGIN)
2495 cFYI(1, (" Guest login"));
2496 /* Do we want to set anything in SesInfo struct when guest login? */
2498 bcc_ptr = pByteArea(smb_buffer_response);
2499 /* response can have either 3 or 4 word count - Samba sends 3 */
2501 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2502 if (SecurityBlob2->MessageType != NtLmChallenge) {
2503 cFYI(1,
2504 ("Unexpected NTLMSSP message type received %d",
2505 SecurityBlob2->MessageType));
2506 } else if (ses) {
2507 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2508 cFYI(1, ("UID = %d ", ses->Suid));
2509 if ((pSMBr->resp.hdr.WordCount == 3)
2510 || ((pSMBr->resp.hdr.WordCount == 4)
2511 && (blob_len <
2512 pSMBr->resp.ByteCount))) {
2514 if (pSMBr->resp.hdr.WordCount == 4) {
2515 bcc_ptr += blob_len;
2516 cFYI(1,
2517 ("Security Blob Length %d ",
2518 blob_len));
2521 cFYI(1, ("NTLMSSP Challenge rcvd "));
2523 memcpy(ses->server->cryptKey,
2524 SecurityBlob2->Challenge,
2525 CIFS_CRYPTO_KEY_SIZE);
2526 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2527 *pNTLMv2_flag = TRUE;
2529 if((SecurityBlob2->NegotiateFlags &
2530 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2531 || (sign_CIFS_PDUs > 1))
2532 ses->server->secMode |=
2533 SECMODE_SIGN_REQUIRED;
2534 if ((SecurityBlob2->NegotiateFlags &
2535 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2536 ses->server->secMode |=
2537 SECMODE_SIGN_ENABLED;
2539 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2540 if ((long) (bcc_ptr) % 2) {
2541 remaining_words =
2542 (BCC(smb_buffer_response)
2543 - 1) / 2;
2544 bcc_ptr++; /* Unicode strings must be word aligned */
2545 } else {
2546 remaining_words =
2548 (smb_buffer_response) / 2;
2550 len =
2551 UniStrnlen((wchar_t *) bcc_ptr,
2552 remaining_words - 1);
2553 /* We look for obvious messed up bcc or strings in response so we do not go off
2554 the end since (at least) WIN2K and Windows XP have a major bug in not null
2555 terminating last Unicode string in response */
2556 ses->serverOS =
2557 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2558 cifs_strfromUCS_le(ses->serverOS,
2559 (wchar_t *)
2560 bcc_ptr, len,
2561 nls_codepage);
2562 bcc_ptr += 2 * (len + 1);
2563 remaining_words -= len + 1;
2564 ses->serverOS[2 * len] = 0;
2565 ses->serverOS[1 + (2 * len)] = 0;
2566 if (remaining_words > 0) {
2567 len = UniStrnlen((wchar_t *)
2568 bcc_ptr,
2569 remaining_words
2570 - 1);
2571 ses->serverNOS =
2572 kcalloc(1, 2 * (len + 1),
2573 GFP_KERNEL);
2574 cifs_strfromUCS_le(ses->
2575 serverNOS,
2576 (wchar_t *)
2577 bcc_ptr,
2578 len,
2579 nls_codepage);
2580 bcc_ptr += 2 * (len + 1);
2581 ses->serverNOS[2 * len] = 0;
2582 ses->serverNOS[1 +
2583 (2 * len)] = 0;
2584 remaining_words -= len + 1;
2585 if (remaining_words > 0) {
2586 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2587 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2588 ses->serverDomain =
2589 kcalloc(1, 2 *
2590 (len +
2592 GFP_KERNEL);
2593 cifs_strfromUCS_le
2594 (ses->
2595 serverDomain,
2596 (wchar_t *)
2597 bcc_ptr, len,
2598 nls_codepage);
2599 bcc_ptr +=
2600 2 * (len + 1);
2601 ses->
2602 serverDomain[2
2603 * len]
2604 = 0;
2605 ses->
2606 serverDomain[1
2610 len)]
2611 = 0;
2612 } /* else no more room so create dummy domain string */
2613 else
2614 ses->serverDomain =
2615 kcalloc(1, 2,
2616 GFP_KERNEL);
2617 } else { /* no room so create dummy domain and NOS string */
2618 ses->serverDomain =
2619 kcalloc(1, 2, GFP_KERNEL);
2620 ses->serverNOS =
2621 kcalloc(1, 2, GFP_KERNEL);
2623 } else { /* ASCII */
2624 len = strnlen(bcc_ptr, 1024);
2625 if (((long) bcc_ptr + len) - (long)
2626 pByteArea(smb_buffer_response)
2627 <= BCC(smb_buffer_response)) {
2628 ses->serverOS =
2629 kcalloc(1, len + 1,
2630 GFP_KERNEL);
2631 strncpy(ses->serverOS,
2632 bcc_ptr, len);
2634 bcc_ptr += len;
2635 bcc_ptr[0] = 0; /* null terminate string */
2636 bcc_ptr++;
2638 len = strnlen(bcc_ptr, 1024);
2639 ses->serverNOS =
2640 kcalloc(1, len + 1,
2641 GFP_KERNEL);
2642 strncpy(ses->serverNOS, bcc_ptr, len);
2643 bcc_ptr += len;
2644 bcc_ptr[0] = 0;
2645 bcc_ptr++;
2647 len = strnlen(bcc_ptr, 1024);
2648 ses->serverDomain =
2649 kcalloc(1, len + 1,
2650 GFP_KERNEL);
2651 strncpy(ses->serverDomain, bcc_ptr, len);
2652 bcc_ptr += len;
2653 bcc_ptr[0] = 0;
2654 bcc_ptr++;
2655 } else
2656 cFYI(1,
2657 ("Variable field of length %d extends beyond end of smb ",
2658 len));
2660 } else {
2661 cERROR(1,
2662 (" Security Blob Length extends beyond end of SMB"));
2664 } else {
2665 cERROR(1, ("No session structure passed in."));
2667 } else {
2668 cERROR(1,
2669 (" Invalid Word count %d: ",
2670 smb_buffer_response->WordCount));
2671 rc = -EIO;
2674 if (smb_buffer)
2675 cifs_buf_release(smb_buffer);
2677 return rc;
2679 static int
2680 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2681 char *ntlm_session_key, int ntlmv2_flag,
2682 const struct nls_table *nls_codepage)
2684 struct smb_hdr *smb_buffer;
2685 struct smb_hdr *smb_buffer_response;
2686 SESSION_SETUP_ANDX *pSMB;
2687 SESSION_SETUP_ANDX *pSMBr;
2688 char *bcc_ptr;
2689 char *user;
2690 char *domain;
2691 int rc = 0;
2692 int remaining_words = 0;
2693 int bytes_returned = 0;
2694 int len;
2695 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2696 PAUTHENTICATE_MESSAGE SecurityBlob;
2697 __u32 negotiate_flags, capabilities;
2698 __u16 count;
2700 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2701 if(ses == NULL)
2702 return -EINVAL;
2703 user = ses->userName;
2704 domain = ses->domainName;
2705 smb_buffer = cifs_buf_get();
2706 if (smb_buffer == NULL) {
2707 return -ENOMEM;
2709 smb_buffer_response = smb_buffer;
2710 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2711 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2713 /* send SMBsessionSetup here */
2714 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2715 NULL /* no tCon exists yet */ , 12 /* wct */ );
2716 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2717 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2718 pSMB->req.AndXCommand = 0xFF;
2719 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2720 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2722 pSMB->req.hdr.Uid = ses->Suid;
2724 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2725 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2727 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2728 CAP_EXTENDED_SECURITY;
2729 if (ses->capabilities & CAP_UNICODE) {
2730 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2731 capabilities |= CAP_UNICODE;
2733 if (ses->capabilities & CAP_STATUS32) {
2734 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2735 capabilities |= CAP_STATUS32;
2737 if (ses->capabilities & CAP_DFS) {
2738 smb_buffer->Flags2 |= SMBFLG2_DFS;
2739 capabilities |= CAP_DFS;
2741 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2743 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2744 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2745 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2746 SecurityBlob->MessageType = NtLmAuthenticate;
2747 bcc_ptr += SecurityBlobLength;
2748 negotiate_flags =
2749 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2750 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2751 0x80000000 | NTLMSSP_NEGOTIATE_128;
2752 if(sign_CIFS_PDUs)
2753 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2754 if(ntlmv2_flag)
2755 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2757 /* setup pointers to domain name and workstation name */
2759 SecurityBlob->WorkstationName.Buffer = 0;
2760 SecurityBlob->WorkstationName.Length = 0;
2761 SecurityBlob->WorkstationName.MaximumLength = 0;
2762 SecurityBlob->SessionKey.Length = 0;
2763 SecurityBlob->SessionKey.MaximumLength = 0;
2764 SecurityBlob->SessionKey.Buffer = 0;
2766 SecurityBlob->LmChallengeResponse.Length = 0;
2767 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2768 SecurityBlob->LmChallengeResponse.Buffer = 0;
2770 SecurityBlob->NtChallengeResponse.Length =
2771 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2772 SecurityBlob->NtChallengeResponse.MaximumLength =
2773 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2774 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2775 SecurityBlob->NtChallengeResponse.Buffer =
2776 cpu_to_le32(SecurityBlobLength);
2777 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2778 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2780 if (ses->capabilities & CAP_UNICODE) {
2781 if (domain == NULL) {
2782 SecurityBlob->DomainName.Buffer = 0;
2783 SecurityBlob->DomainName.Length = 0;
2784 SecurityBlob->DomainName.MaximumLength = 0;
2785 } else {
2786 __u16 len =
2787 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2788 nls_codepage);
2789 len *= 2;
2790 SecurityBlob->DomainName.MaximumLength =
2791 cpu_to_le16(len);
2792 SecurityBlob->DomainName.Buffer =
2793 cpu_to_le32(SecurityBlobLength);
2794 bcc_ptr += len;
2795 SecurityBlobLength += len;
2796 SecurityBlob->DomainName.Length =
2797 cpu_to_le16(len);
2799 if (user == NULL) {
2800 SecurityBlob->UserName.Buffer = 0;
2801 SecurityBlob->UserName.Length = 0;
2802 SecurityBlob->UserName.MaximumLength = 0;
2803 } else {
2804 __u16 len =
2805 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2806 nls_codepage);
2807 len *= 2;
2808 SecurityBlob->UserName.MaximumLength =
2809 cpu_to_le16(len);
2810 SecurityBlob->UserName.Buffer =
2811 cpu_to_le32(SecurityBlobLength);
2812 bcc_ptr += len;
2813 SecurityBlobLength += len;
2814 SecurityBlob->UserName.Length =
2815 cpu_to_le16(len);
2818 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2819 SecurityBlob->WorkstationName.Length *= 2;
2820 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2821 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2822 bcc_ptr += SecurityBlob->WorkstationName.Length;
2823 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2824 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2826 if ((long) bcc_ptr % 2) {
2827 *bcc_ptr = 0;
2828 bcc_ptr++;
2830 bytes_returned =
2831 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2832 32, nls_codepage);
2833 bcc_ptr += 2 * bytes_returned;
2834 bytes_returned =
2835 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2836 nls_codepage);
2837 bcc_ptr += 2 * bytes_returned;
2838 bcc_ptr += 2; /* null term version string */
2839 bytes_returned =
2840 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2841 64, nls_codepage);
2842 bcc_ptr += 2 * bytes_returned;
2843 *(bcc_ptr + 1) = 0;
2844 *(bcc_ptr + 2) = 0;
2845 bcc_ptr += 2; /* null terminate network opsys string */
2846 *(bcc_ptr + 1) = 0;
2847 *(bcc_ptr + 2) = 0;
2848 bcc_ptr += 2; /* null domain */
2849 } else { /* ASCII */
2850 if (domain == NULL) {
2851 SecurityBlob->DomainName.Buffer = 0;
2852 SecurityBlob->DomainName.Length = 0;
2853 SecurityBlob->DomainName.MaximumLength = 0;
2854 } else {
2855 __u16 len;
2856 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2857 strncpy(bcc_ptr, domain, 63);
2858 len = strnlen(domain, 64);
2859 SecurityBlob->DomainName.MaximumLength =
2860 cpu_to_le16(len);
2861 SecurityBlob->DomainName.Buffer =
2862 cpu_to_le32(SecurityBlobLength);
2863 bcc_ptr += len;
2864 SecurityBlobLength += len;
2865 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2867 if (user == NULL) {
2868 SecurityBlob->UserName.Buffer = 0;
2869 SecurityBlob->UserName.Length = 0;
2870 SecurityBlob->UserName.MaximumLength = 0;
2871 } else {
2872 __u16 len;
2873 strncpy(bcc_ptr, user, 63);
2874 len = strnlen(user, 64);
2875 SecurityBlob->UserName.MaximumLength =
2876 cpu_to_le16(len);
2877 SecurityBlob->UserName.Buffer =
2878 cpu_to_le32(SecurityBlobLength);
2879 bcc_ptr += len;
2880 SecurityBlobLength += len;
2881 SecurityBlob->UserName.Length = cpu_to_le16(len);
2883 /* BB fill in our workstation name if known BB */
2885 strcpy(bcc_ptr, "Linux version ");
2886 bcc_ptr += strlen("Linux version ");
2887 strcpy(bcc_ptr, system_utsname.release);
2888 bcc_ptr += strlen(system_utsname.release) + 1;
2889 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2890 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2891 bcc_ptr++; /* null domain */
2892 *bcc_ptr = 0;
2894 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2895 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2896 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2897 smb_buffer->smb_buf_length += count;
2898 pSMB->req.ByteCount = cpu_to_le16(count);
2900 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2901 &bytes_returned, 1);
2902 if (rc) {
2903 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2904 } else if ((smb_buffer_response->WordCount == 3)
2905 || (smb_buffer_response->WordCount == 4)) {
2906 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2907 __u16 blob_len =
2908 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2909 if (action & GUEST_LOGIN)
2910 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2911 /* if(SecurityBlob2->MessageType != NtLm??){
2912 cFYI("Unexpected message type on auth response is %d "));
2913 } */
2914 if (ses) {
2915 cFYI(1,
2916 ("Does UID on challenge %d match auth response UID %d ",
2917 ses->Suid, smb_buffer_response->Uid));
2918 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2919 bcc_ptr = pByteArea(smb_buffer_response);
2920 /* response can have either 3 or 4 word count - Samba sends 3 */
2921 if ((pSMBr->resp.hdr.WordCount == 3)
2922 || ((pSMBr->resp.hdr.WordCount == 4)
2923 && (blob_len <
2924 pSMBr->resp.ByteCount))) {
2925 if (pSMBr->resp.hdr.WordCount == 4) {
2926 bcc_ptr +=
2927 blob_len;
2928 cFYI(1,
2929 ("Security Blob Length %d ",
2930 blob_len));
2933 cFYI(1,
2934 ("NTLMSSP response to Authenticate "));
2936 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2937 if ((long) (bcc_ptr) % 2) {
2938 remaining_words =
2939 (BCC(smb_buffer_response)
2940 - 1) / 2;
2941 bcc_ptr++; /* Unicode strings must be word aligned */
2942 } else {
2943 remaining_words = BCC(smb_buffer_response) / 2;
2945 len =
2946 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2947 /* We look for obvious messed up bcc or strings in response so we do not go off
2948 the end since (at least) WIN2K and Windows XP have a major bug in not null
2949 terminating last Unicode string in response */
2950 ses->serverOS =
2951 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2952 cifs_strfromUCS_le(ses->serverOS,
2953 (wchar_t *)
2954 bcc_ptr, len,
2955 nls_codepage);
2956 bcc_ptr += 2 * (len + 1);
2957 remaining_words -= len + 1;
2958 ses->serverOS[2 * len] = 0;
2959 ses->serverOS[1 + (2 * len)] = 0;
2960 if (remaining_words > 0) {
2961 len = UniStrnlen((wchar_t *)
2962 bcc_ptr,
2963 remaining_words
2964 - 1);
2965 ses->serverNOS =
2966 kcalloc(1, 2 * (len + 1),
2967 GFP_KERNEL);
2968 cifs_strfromUCS_le(ses->
2969 serverNOS,
2970 (wchar_t *)
2971 bcc_ptr,
2972 len,
2973 nls_codepage);
2974 bcc_ptr += 2 * (len + 1);
2975 ses->serverNOS[2 * len] = 0;
2976 ses->serverNOS[1+(2*len)] = 0;
2977 remaining_words -= len + 1;
2978 if (remaining_words > 0) {
2979 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2980 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2981 ses->serverDomain =
2982 kcalloc(1, 2 *
2983 (len +
2985 GFP_KERNEL);
2986 cifs_strfromUCS_le
2987 (ses->
2988 serverDomain,
2989 (wchar_t *)
2990 bcc_ptr, len,
2991 nls_codepage);
2992 bcc_ptr +=
2993 2 * (len + 1);
2994 ses->
2995 serverDomain[2
2996 * len]
2997 = 0;
2998 ses->
2999 serverDomain[1
3003 len)]
3004 = 0;
3005 } /* else no more room so create dummy domain string */
3006 else
3007 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
3008 } else { /* no room so create dummy domain and NOS string */
3009 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3010 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
3012 } else { /* ASCII */
3013 len = strnlen(bcc_ptr, 1024);
3014 if (((long) bcc_ptr + len) -
3015 (long) pByteArea(smb_buffer_response)
3016 <= BCC(smb_buffer_response)) {
3017 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
3018 strncpy(ses->serverOS,bcc_ptr, len);
3020 bcc_ptr += len;
3021 bcc_ptr[0] = 0; /* null terminate the string */
3022 bcc_ptr++;
3024 len = strnlen(bcc_ptr, 1024);
3025 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
3026 strncpy(ses->serverNOS, bcc_ptr, len);
3027 bcc_ptr += len;
3028 bcc_ptr[0] = 0;
3029 bcc_ptr++;
3031 len = strnlen(bcc_ptr, 1024);
3032 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
3033 strncpy(ses->serverDomain, bcc_ptr, len);
3034 bcc_ptr += len;
3035 bcc_ptr[0] = 0;
3036 bcc_ptr++;
3037 } else
3038 cFYI(1,
3039 ("Variable field of length %d extends beyond end of smb ",
3040 len));
3042 } else {
3043 cERROR(1,
3044 (" Security Blob Length extends beyond end of SMB"));
3046 } else {
3047 cERROR(1, ("No session structure passed in."));
3049 } else {
3050 cERROR(1,
3051 (" Invalid Word count %d: ",
3052 smb_buffer_response->WordCount));
3053 rc = -EIO;
3056 if (smb_buffer)
3057 cifs_buf_release(smb_buffer);
3059 return rc;
3063 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3064 const char *tree, struct cifsTconInfo *tcon,
3065 const struct nls_table *nls_codepage)
3067 struct smb_hdr *smb_buffer;
3068 struct smb_hdr *smb_buffer_response;
3069 TCONX_REQ *pSMB;
3070 TCONX_RSP *pSMBr;
3071 unsigned char *bcc_ptr;
3072 int rc = 0;
3073 int length;
3074 __u16 count;
3076 if (ses == NULL)
3077 return -EIO;
3079 smb_buffer = cifs_buf_get();
3080 if (smb_buffer == NULL) {
3081 return -ENOMEM;
3083 smb_buffer_response = smb_buffer;
3085 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3086 NULL /*no tid */ , 4 /*wct */ );
3087 smb_buffer->Uid = ses->Suid;
3088 pSMB = (TCONX_REQ *) smb_buffer;
3089 pSMBr = (TCONX_RSP *) smb_buffer_response;
3091 pSMB->AndXCommand = 0xFF;
3092 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3093 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3094 bcc_ptr = &pSMB->Password[0];
3095 bcc_ptr++; /* skip password */
3097 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3098 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3100 if (ses->capabilities & CAP_STATUS32) {
3101 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3103 if (ses->capabilities & CAP_DFS) {
3104 smb_buffer->Flags2 |= SMBFLG2_DFS;
3106 if (ses->capabilities & CAP_UNICODE) {
3107 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3108 length =
3109 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3110 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3111 bcc_ptr += 2; /* skip trailing null */
3112 } else { /* ASCII */
3114 strcpy(bcc_ptr, tree);
3115 bcc_ptr += strlen(tree) + 1;
3117 strcpy(bcc_ptr, "?????");
3118 bcc_ptr += strlen("?????");
3119 bcc_ptr += 1;
3120 count = bcc_ptr - &pSMB->Password[0];
3121 pSMB->hdr.smb_buf_length += count;
3122 pSMB->ByteCount = cpu_to_le16(count);
3124 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3126 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3127 /* above now done in SendReceive */
3128 if ((rc == 0) && (tcon != NULL)) {
3129 tcon->tidStatus = CifsGood;
3130 tcon->tid = smb_buffer_response->Tid;
3131 bcc_ptr = pByteArea(smb_buffer_response);
3132 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3133 /* skip service field (NB: this field is always ASCII) */
3134 bcc_ptr += length + 1;
3135 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3136 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3137 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3138 if ((bcc_ptr + (2 * length)) -
3139 pByteArea(smb_buffer_response) <=
3140 BCC(smb_buffer_response)) {
3141 if(tcon->nativeFileSystem)
3142 kfree(tcon->nativeFileSystem);
3143 tcon->nativeFileSystem =
3144 kcalloc(1, length + 2, GFP_KERNEL);
3145 cifs_strfromUCS_le(tcon->nativeFileSystem,
3146 (wchar_t *) bcc_ptr,
3147 length, nls_codepage);
3148 bcc_ptr += 2 * length;
3149 bcc_ptr[0] = 0; /* null terminate the string */
3150 bcc_ptr[1] = 0;
3151 bcc_ptr += 2;
3153 /* else do not bother copying these informational fields */
3154 } else {
3155 length = strnlen(bcc_ptr, 1024);
3156 if ((bcc_ptr + length) -
3157 pByteArea(smb_buffer_response) <=
3158 BCC(smb_buffer_response)) {
3159 if(tcon->nativeFileSystem)
3160 kfree(tcon->nativeFileSystem);
3161 tcon->nativeFileSystem =
3162 kcalloc(1, length + 1, GFP_KERNEL);
3163 strncpy(tcon->nativeFileSystem, bcc_ptr,
3164 length);
3166 /* else do not bother copying these informational fields */
3168 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3169 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3170 } else if ((rc == 0) && tcon == NULL) {
3171 /* all we need to save for IPC$ connection */
3172 ses->ipc_tid = smb_buffer_response->Tid;
3175 if (smb_buffer)
3176 cifs_buf_release(smb_buffer);
3177 return rc;
3181 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3183 int rc = 0;
3184 int xid;
3185 struct cifsSesInfo *ses = NULL;
3186 struct task_struct *cifsd_task;
3188 xid = GetXid();
3190 if (cifs_sb->tcon) {
3191 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3192 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3193 if (rc == -EBUSY) {
3194 FreeXid(xid);
3195 return 0;
3197 tconInfoFree(cifs_sb->tcon);
3198 if ((ses) && (ses->server)) {
3199 /* save off task so we do not refer to ses later */
3200 cifsd_task = ses->server->tsk;
3201 cFYI(1, ("About to do SMBLogoff "));
3202 rc = CIFSSMBLogoff(xid, ses);
3203 if (rc == -EBUSY) {
3204 FreeXid(xid);
3205 return 0;
3206 } else if (rc == -ESHUTDOWN) {
3207 cFYI(1,("Waking up socket by sending it signal"));
3208 if(cifsd_task)
3209 send_sig(SIGKILL,cifsd_task,1);
3210 rc = 0;
3211 } /* else - we have an smb session
3212 left on this socket do not kill cifsd */
3213 } else
3214 cFYI(1, ("No session or bad tcon"));
3217 cifs_sb->tcon = NULL;
3218 if (ses) {
3219 set_current_state(TASK_INTERRUPTIBLE);
3220 schedule_timeout(HZ / 2);
3222 if (ses)
3223 sesInfoFree(ses);
3225 FreeXid(xid);
3226 return rc; /* BB check if we should always return zero here */
3229 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3230 struct nls_table * nls_info)
3232 int rc = 0;
3233 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3234 int ntlmv2_flag = FALSE;
3235 int first_time = 0;
3237 /* what if server changes its buffer size after dropping the session? */
3238 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3239 rc = CIFSSMBNegotiate(xid, pSesInfo);
3240 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3241 rc = CIFSSMBNegotiate(xid, pSesInfo);
3242 if(rc == -EAGAIN)
3243 rc = -EHOSTDOWN;
3245 if(rc == 0) {
3246 spin_lock(&GlobalMid_Lock);
3247 if(pSesInfo->server->tcpStatus != CifsExiting)
3248 pSesInfo->server->tcpStatus = CifsGood;
3249 else
3250 rc = -EHOSTDOWN;
3251 spin_unlock(&GlobalMid_Lock);
3254 first_time = 1;
3256 if (!rc) {
3257 pSesInfo->capabilities = pSesInfo->server->capabilities;
3258 if(linuxExtEnabled == 0)
3259 pSesInfo->capabilities &= (~CAP_UNIX);
3260 /* pSesInfo->sequence_number = 0;*/
3261 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3262 pSesInfo->server->secMode,
3263 pSesInfo->server->capabilities,
3264 pSesInfo->server->timeZone));
3265 if (extended_security
3266 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3267 && (pSesInfo->server->secType == NTLMSSP)) {
3268 cFYI(1, ("New style sesssetup "));
3269 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3270 NULL /* security blob */,
3271 0 /* blob length */,
3272 nls_info);
3273 } else if (extended_security
3274 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3275 && (pSesInfo->server->secType == RawNTLMSSP)) {
3276 cFYI(1, ("NTLMSSP sesssetup "));
3277 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3278 pSesInfo,
3279 &ntlmv2_flag,
3280 nls_info);
3281 if (!rc) {
3282 if(ntlmv2_flag) {
3283 char * v2_response;
3284 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3285 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3286 nls_info)) {
3287 rc = -ENOMEM;
3288 goto ss_err_exit;
3289 } else
3290 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3291 if(v2_response) {
3292 CalcNTLMv2_response(pSesInfo,v2_response);
3293 /* if(first_time)
3294 cifs_calculate_ntlmv2_mac_key(
3295 pSesInfo->server->mac_signing_key,
3296 response, ntlm_session_key, */
3297 kfree(v2_response);
3298 /* BB Put dummy sig in SessSetup PDU? */
3299 } else {
3300 rc = -ENOMEM;
3301 goto ss_err_exit;
3304 } else {
3305 SMBNTencrypt(pSesInfo->password,
3306 pSesInfo->server->cryptKey,
3307 ntlm_session_key);
3309 if(first_time)
3310 cifs_calculate_mac_key(
3311 pSesInfo->server->mac_signing_key,
3312 ntlm_session_key,
3313 pSesInfo->password);
3315 /* for better security the weaker lanman hash not sent
3316 in AuthSessSetup so we no longer calculate it */
3318 rc = CIFSNTLMSSPAuthSessSetup(xid,
3319 pSesInfo,
3320 ntlm_session_key,
3321 ntlmv2_flag,
3322 nls_info);
3324 } else { /* old style NTLM 0.12 session setup */
3325 SMBNTencrypt(pSesInfo->password,
3326 pSesInfo->server->cryptKey,
3327 ntlm_session_key);
3329 if(first_time)
3330 cifs_calculate_mac_key(
3331 pSesInfo->server->mac_signing_key,
3332 ntlm_session_key, pSesInfo->password);
3334 rc = CIFSSessSetup(xid, pSesInfo,
3335 ntlm_session_key, nls_info);
3337 if (rc) {
3338 cERROR(1,("Send error in SessSetup = %d",rc));
3339 } else {
3340 cFYI(1,("CIFS Session Established successfully"));
3341 pSesInfo->status = CifsGood;
3344 ss_err_exit:
3345 return rc;