[ARM] 3115/1: small optimizations to exception vector entry code
[linux-2.6/x86.git] / fs / cifs / connect.c
blobd74367a08d513dd4cf6bb6a3aa090996972ea7f5
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 <linux/completion.h>
33 #include <linux/pagevec.h>
34 #include <asm/uaccess.h>
35 #include <asm/processor.h>
36 #include "cifspdu.h"
37 #include "cifsglob.h"
38 #include "cifsproto.h"
39 #include "cifs_unicode.h"
40 #include "cifs_debug.h"
41 #include "cifs_fs_sb.h"
42 #include "ntlmssp.h"
43 #include "nterr.h"
44 #include "rfc1002pdu.h"
46 #define CIFS_PORT 445
47 #define RFC1001_PORT 139
49 static DECLARE_COMPLETION(cifsd_complete);
51 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
52 unsigned char *p24);
53 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
54 unsigned char *p24);
56 extern mempool_t *cifs_req_poolp;
58 struct smb_vol {
59 char *username;
60 char *password;
61 char *domainname;
62 char *UNC;
63 char *UNCip;
64 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
65 char *iocharset; /* local code page for mapping to and from Unicode */
66 char source_rfc1001_name[16]; /* netbios name of client */
67 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
68 uid_t linux_uid;
69 gid_t linux_gid;
70 mode_t file_mode;
71 mode_t dir_mode;
72 unsigned rw:1;
73 unsigned retry:1;
74 unsigned intr:1;
75 unsigned setuids:1;
76 unsigned noperm:1;
77 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
78 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
79 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
80 unsigned direct_io:1;
81 unsigned remap:1; /* set to remap seven reserved chars in filenames */
82 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
83 unsigned sfu_emul:1;
84 unsigned nocase; /* request case insensitive filenames */
85 unsigned nobrl; /* disable sending byte range locks to srv */
86 unsigned int rsize;
87 unsigned int wsize;
88 unsigned int sockopt;
89 unsigned short int port;
92 static int ipv4_connect(struct sockaddr_in *psin_server,
93 struct socket **csocket,
94 char * netb_name,
95 char * server_netb_name);
96 static int ipv6_connect(struct sockaddr_in6 *psin_server,
97 struct socket **csocket);
101 * cifs tcp session reconnection
103 * mark tcp session as reconnecting so temporarily locked
104 * mark all smb sessions as reconnecting for tcp session
105 * reconnect tcp session
106 * wake up waiters on reconnection? - (not needed currently)
110 cifs_reconnect(struct TCP_Server_Info *server)
112 int rc = 0;
113 struct list_head *tmp;
114 struct cifsSesInfo *ses;
115 struct cifsTconInfo *tcon;
116 struct mid_q_entry * mid_entry;
118 spin_lock(&GlobalMid_Lock);
119 if(server->tcpStatus == CifsExiting) {
120 /* the demux thread will exit normally
121 next time through the loop */
122 spin_unlock(&GlobalMid_Lock);
123 return rc;
124 } else
125 server->tcpStatus = CifsNeedReconnect;
126 spin_unlock(&GlobalMid_Lock);
127 server->maxBuf = 0;
129 cFYI(1, ("Reconnecting tcp session"));
131 /* before reconnecting the tcp session, mark the smb session (uid)
132 and the tid bad so they are not used until reconnected */
133 read_lock(&GlobalSMBSeslock);
134 list_for_each(tmp, &GlobalSMBSessionList) {
135 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
136 if (ses->server) {
137 if (ses->server == server) {
138 ses->status = CifsNeedReconnect;
139 ses->ipc_tid = 0;
142 /* else tcp and smb sessions need reconnection */
144 list_for_each(tmp, &GlobalTreeConnectionList) {
145 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
146 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
147 tcon->tidStatus = CifsNeedReconnect;
150 read_unlock(&GlobalSMBSeslock);
151 /* do not want to be sending data on a socket we are freeing */
152 down(&server->tcpSem);
153 if(server->ssocket) {
154 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
155 server->ssocket->flags));
156 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
157 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
158 server->ssocket->flags));
159 sock_release(server->ssocket);
160 server->ssocket = NULL;
163 spin_lock(&GlobalMid_Lock);
164 list_for_each(tmp, &server->pending_mid_q) {
165 mid_entry = list_entry(tmp, struct
166 mid_q_entry,
167 qhead);
168 if(mid_entry) {
169 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
170 /* Mark other intransit requests as needing
171 retry so we do not immediately mark the
172 session bad again (ie after we reconnect
173 below) as they timeout too */
174 mid_entry->midState = MID_RETRY_NEEDED;
178 spin_unlock(&GlobalMid_Lock);
179 up(&server->tcpSem);
181 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
183 if(server->protocolType == IPV6) {
184 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
185 } else {
186 rc = ipv4_connect(&server->addr.sockAddr,
187 &server->ssocket,
188 server->workstation_RFC1001_name,
189 server->server_RFC1001_name);
191 if(rc) {
192 cFYI(1,("reconnect error %d",rc));
193 msleep(3000);
194 } else {
195 atomic_inc(&tcpSesReconnectCount);
196 spin_lock(&GlobalMid_Lock);
197 if(server->tcpStatus != CifsExiting)
198 server->tcpStatus = CifsGood;
199 server->sequence_number = 0;
200 spin_unlock(&GlobalMid_Lock);
201 /* atomic_set(&server->inFlight,0);*/
202 wake_up(&server->response_q);
205 return rc;
209 return codes:
210 0 not a transact2, or all data present
211 >0 transact2 with that much data missing
212 -EINVAL = invalid transact2
215 static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
217 struct smb_t2_rsp * pSMBt;
218 int total_data_size;
219 int data_in_this_rsp;
220 int remaining;
222 if(pSMB->Command != SMB_COM_TRANSACTION2)
223 return 0;
225 /* check for plausible wct, bcc and t2 data and parm sizes */
226 /* check for parm and data offset going beyond end of smb */
227 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
228 cFYI(1,("invalid transact2 word count"));
229 return -EINVAL;
232 pSMBt = (struct smb_t2_rsp *)pSMB;
234 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
235 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
237 remaining = total_data_size - data_in_this_rsp;
239 if(remaining == 0)
240 return 0;
241 else if(remaining < 0) {
242 cFYI(1,("total data %d smaller than data in frame %d",
243 total_data_size, data_in_this_rsp));
244 return -EINVAL;
245 } else {
246 cFYI(1,("missing %d bytes from transact2, check next response",
247 remaining));
248 if(total_data_size > maxBufSize) {
249 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
250 total_data_size,maxBufSize));
251 return -EINVAL;
253 return remaining;
257 static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
259 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
260 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
261 int total_data_size;
262 int total_in_buf;
263 int remaining;
264 int total_in_buf2;
265 char * data_area_of_target;
266 char * data_area_of_buf2;
267 __u16 byte_count;
269 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
271 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
272 cFYI(1,("total data sizes of primary and secondary t2 differ"));
275 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
277 remaining = total_data_size - total_in_buf;
279 if(remaining < 0)
280 return -EINVAL;
282 if(remaining == 0) /* nothing to do, ignore */
283 return 0;
285 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
286 if(remaining < total_in_buf2) {
287 cFYI(1,("transact2 2nd response contains too much data"));
290 /* find end of first SMB data area */
291 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
292 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
293 /* validate target area */
295 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
296 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
298 data_area_of_target += total_in_buf;
300 /* copy second buffer into end of first buffer */
301 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
302 total_in_buf += total_in_buf2;
303 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
304 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
305 byte_count += total_in_buf2;
306 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
308 byte_count = pTargetSMB->smb_buf_length;
309 byte_count += total_in_buf2;
311 /* BB also add check that we are not beyond maximum buffer size */
313 pTargetSMB->smb_buf_length = byte_count;
315 if(remaining == total_in_buf2) {
316 cFYI(1,("found the last secondary response"));
317 return 0; /* we are done */
318 } else /* more responses to go */
319 return 1;
323 static int
324 cifs_demultiplex_thread(struct TCP_Server_Info *server)
326 int length;
327 unsigned int pdu_length, total_read;
328 struct smb_hdr *smb_buffer = NULL;
329 struct smb_hdr *bigbuf = NULL;
330 struct smb_hdr *smallbuf = NULL;
331 struct msghdr smb_msg;
332 struct kvec iov;
333 struct socket *csocket = server->ssocket;
334 struct list_head *tmp;
335 struct cifsSesInfo *ses;
336 struct task_struct *task_to_wake = NULL;
337 struct mid_q_entry *mid_entry;
338 char temp;
339 int isLargeBuf = FALSE;
340 int isMultiRsp;
341 int reconnect;
343 daemonize("cifsd");
344 allow_signal(SIGKILL);
345 current->flags |= PF_MEMALLOC;
346 server->tsk = current; /* save process info to wake at shutdown */
347 cFYI(1, ("Demultiplex PID: %d", current->pid));
348 write_lock(&GlobalSMBSeslock);
349 atomic_inc(&tcpSesAllocCount);
350 length = tcpSesAllocCount.counter;
351 write_unlock(&GlobalSMBSeslock);
352 complete(&cifsd_complete);
353 if(length > 1) {
354 mempool_resize(cifs_req_poolp,
355 length + cifs_min_rcv,
356 GFP_KERNEL);
359 while (server->tcpStatus != CifsExiting) {
360 if (try_to_freeze())
361 continue;
362 if (bigbuf == NULL) {
363 bigbuf = cifs_buf_get();
364 if(bigbuf == NULL) {
365 cERROR(1,("No memory for large SMB response"));
366 msleep(3000);
367 /* retry will check if exiting */
368 continue;
370 } else if(isLargeBuf) {
371 /* we are reusing a dirtry large buf, clear its start */
372 memset(bigbuf, 0, sizeof (struct smb_hdr));
375 if (smallbuf == NULL) {
376 smallbuf = cifs_small_buf_get();
377 if(smallbuf == NULL) {
378 cERROR(1,("No memory for SMB response"));
379 msleep(1000);
380 /* retry will check if exiting */
381 continue;
383 /* beginning of smb buffer is cleared in our buf_get */
384 } else /* if existing small buf clear beginning */
385 memset(smallbuf, 0, sizeof (struct smb_hdr));
387 isLargeBuf = FALSE;
388 isMultiRsp = FALSE;
389 smb_buffer = smallbuf;
390 iov.iov_base = smb_buffer;
391 iov.iov_len = 4;
392 smb_msg.msg_control = NULL;
393 smb_msg.msg_controllen = 0;
394 length =
395 kernel_recvmsg(csocket, &smb_msg,
396 &iov, 1, 4, 0 /* BB see socket.h flags */);
398 if(server->tcpStatus == CifsExiting) {
399 break;
400 } else if (server->tcpStatus == CifsNeedReconnect) {
401 cFYI(1,("Reconnect after server stopped responding"));
402 cifs_reconnect(server);
403 cFYI(1,("call to reconnect done"));
404 csocket = server->ssocket;
405 continue;
406 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
407 msleep(1); /* minimum sleep to prevent looping
408 allowing socket to clear and app threads to set
409 tcpStatus CifsNeedReconnect if server hung */
410 continue;
411 } else if (length <= 0) {
412 if(server->tcpStatus == CifsNew) {
413 cFYI(1,("tcp session abend after SMBnegprot"));
414 /* some servers kill the TCP session rather than
415 returning an SMB negprot error, in which
416 case reconnecting here is not going to help,
417 and so simply return error to mount */
418 break;
420 if(length == -EINTR) {
421 cFYI(1,("cifsd thread killed"));
422 break;
424 cFYI(1,("Reconnect after unexpected peek error %d",
425 length));
426 cifs_reconnect(server);
427 csocket = server->ssocket;
428 wake_up(&server->response_q);
429 continue;
430 } else if (length < 4) {
431 cFYI(1,
432 ("Frame under four bytes received (%d bytes long)",
433 length));
434 cifs_reconnect(server);
435 csocket = server->ssocket;
436 wake_up(&server->response_q);
437 continue;
440 /* The right amount was read from socket - 4 bytes */
441 /* so we can now interpret the length field */
443 /* the first byte big endian of the length field,
444 is actually not part of the length but the type
445 with the most common, zero, as regular data */
446 temp = *((char *) smb_buffer);
448 /* Note that FC 1001 length is big endian on the wire,
449 but we convert it here so it is always manipulated
450 as host byte order */
451 pdu_length = ntohl(smb_buffer->smb_buf_length);
452 smb_buffer->smb_buf_length = pdu_length;
454 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
456 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
457 continue;
458 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
459 cFYI(1,("Good RFC 1002 session rsp"));
460 continue;
461 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
462 /* we get this from Windows 98 instead of
463 an error on SMB negprot response */
464 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
465 pdu_length));
466 if(server->tcpStatus == CifsNew) {
467 /* if nack on negprot (rather than
468 ret of smb negprot error) reconnecting
469 not going to help, ret error to mount */
470 break;
471 } else {
472 /* give server a second to
473 clean up before reconnect attempt */
474 msleep(1000);
475 /* always try 445 first on reconnect
476 since we get NACK on some if we ever
477 connected to port 139 (the NACK is
478 since we do not begin with RFC1001
479 session initialize frame) */
480 server->addr.sockAddr.sin_port =
481 htons(CIFS_PORT);
482 cifs_reconnect(server);
483 csocket = server->ssocket;
484 wake_up(&server->response_q);
485 continue;
487 } else if (temp != (char) 0) {
488 cERROR(1,("Unknown RFC 1002 frame"));
489 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
490 length);
491 cifs_reconnect(server);
492 csocket = server->ssocket;
493 continue;
496 /* else we have an SMB response */
497 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
498 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
499 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
500 length, pdu_length+4));
501 cifs_reconnect(server);
502 csocket = server->ssocket;
503 wake_up(&server->response_q);
504 continue;
507 /* else length ok */
508 reconnect = 0;
510 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
511 isLargeBuf = TRUE;
512 memcpy(bigbuf, smallbuf, 4);
513 smb_buffer = bigbuf;
515 length = 0;
516 iov.iov_base = 4 + (char *)smb_buffer;
517 iov.iov_len = pdu_length;
518 for (total_read = 0; total_read < pdu_length;
519 total_read += length) {
520 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
521 pdu_length - total_read, 0);
522 if((server->tcpStatus == CifsExiting) ||
523 (length == -EINTR)) {
524 /* then will exit */
525 reconnect = 2;
526 break;
527 } else if (server->tcpStatus == CifsNeedReconnect) {
528 cifs_reconnect(server);
529 csocket = server->ssocket;
530 /* Reconnect wakes up rspns q */
531 /* Now we will reread sock */
532 reconnect = 1;
533 break;
534 } else if ((length == -ERESTARTSYS) ||
535 (length == -EAGAIN)) {
536 msleep(1); /* minimum sleep to prevent looping,
537 allowing socket to clear and app
538 threads to set tcpStatus
539 CifsNeedReconnect if server hung*/
540 continue;
541 } else if (length <= 0) {
542 cERROR(1,("Received no data, expecting %d",
543 pdu_length - total_read));
544 cifs_reconnect(server);
545 csocket = server->ssocket;
546 reconnect = 1;
547 break;
550 if(reconnect == 2)
551 break;
552 else if(reconnect == 1)
553 continue;
555 length += 4; /* account for rfc1002 hdr */
558 dump_smb(smb_buffer, length);
559 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
560 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
561 continue;
565 task_to_wake = NULL;
566 spin_lock(&GlobalMid_Lock);
567 list_for_each(tmp, &server->pending_mid_q) {
568 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
570 if ((mid_entry->mid == smb_buffer->Mid) &&
571 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
572 (mid_entry->command == smb_buffer->Command)) {
573 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
574 /* We have a multipart transact2 resp */
575 isMultiRsp = TRUE;
576 if(mid_entry->resp_buf) {
577 /* merge response - fix up 1st*/
578 if(coalesce_t2(smb_buffer,
579 mid_entry->resp_buf)) {
580 break;
581 } else {
582 /* all parts received */
583 goto multi_t2_fnd;
585 } else {
586 if(!isLargeBuf) {
587 cERROR(1,("1st trans2 resp needs bigbuf"));
588 /* BB maybe we can fix this up, switch
589 to already allocated large buffer? */
590 } else {
591 /* Have first buffer */
592 mid_entry->resp_buf =
593 smb_buffer;
594 mid_entry->largeBuf = 1;
595 bigbuf = NULL;
598 break;
600 mid_entry->resp_buf = smb_buffer;
601 if(isLargeBuf)
602 mid_entry->largeBuf = 1;
603 else
604 mid_entry->largeBuf = 0;
605 multi_t2_fnd:
606 task_to_wake = mid_entry->tsk;
607 mid_entry->midState = MID_RESPONSE_RECEIVED;
608 #ifdef CONFIG_CIFS_STATS2
609 mid_entry->when_received = jiffies;
610 #endif
611 break;
614 spin_unlock(&GlobalMid_Lock);
615 if (task_to_wake) {
616 /* Was previous buf put in mpx struct for multi-rsp? */
617 if(!isMultiRsp) {
618 /* smb buffer will be freed by user thread */
619 if(isLargeBuf) {
620 bigbuf = NULL;
621 } else
622 smallbuf = NULL;
624 wake_up_process(task_to_wake);
625 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
626 && (isMultiRsp == FALSE)) {
627 cERROR(1, ("No task to wake, unknown frame rcvd!"));
628 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
629 sizeof(struct smb_hdr));
631 } /* end while !EXITING */
633 spin_lock(&GlobalMid_Lock);
634 server->tcpStatus = CifsExiting;
635 server->tsk = NULL;
636 /* check if we have blocked requests that need to free */
637 /* Note that cifs_max_pending is normally 50, but
638 can be set at module install time to as little as two */
639 if(atomic_read(&server->inFlight) >= cifs_max_pending)
640 atomic_set(&server->inFlight, cifs_max_pending - 1);
641 /* We do not want to set the max_pending too low or we
642 could end up with the counter going negative */
643 spin_unlock(&GlobalMid_Lock);
644 /* Although there should not be any requests blocked on
645 this queue it can not hurt to be paranoid and try to wake up requests
646 that may haven been blocked when more than 50 at time were on the wire
647 to the same server - they now will see the session is in exit state
648 and get out of SendReceive. */
649 wake_up_all(&server->request_q);
650 /* give those requests time to exit */
651 msleep(125);
653 if(server->ssocket) {
654 sock_release(csocket);
655 server->ssocket = NULL;
657 /* buffer usuallly freed in free_mid - need to free it here on exit */
658 if (bigbuf != NULL)
659 cifs_buf_release(bigbuf);
660 if (smallbuf != NULL)
661 cifs_small_buf_release(smallbuf);
663 read_lock(&GlobalSMBSeslock);
664 if (list_empty(&server->pending_mid_q)) {
665 /* loop through server session structures attached to this and
666 mark them dead */
667 list_for_each(tmp, &GlobalSMBSessionList) {
668 ses =
669 list_entry(tmp, struct cifsSesInfo,
670 cifsSessionList);
671 if (ses->server == server) {
672 ses->status = CifsExiting;
673 ses->server = NULL;
676 read_unlock(&GlobalSMBSeslock);
677 } else {
678 /* although we can not zero the server struct pointer yet,
679 since there are active requests which may depnd on them,
680 mark the corresponding SMB sessions as exiting too */
681 list_for_each(tmp, &GlobalSMBSessionList) {
682 ses = list_entry(tmp, struct cifsSesInfo,
683 cifsSessionList);
684 if (ses->server == server) {
685 ses->status = CifsExiting;
689 spin_lock(&GlobalMid_Lock);
690 list_for_each(tmp, &server->pending_mid_q) {
691 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
692 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
693 cFYI(1,
694 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
695 task_to_wake = mid_entry->tsk;
696 if(task_to_wake) {
697 wake_up_process(task_to_wake);
701 spin_unlock(&GlobalMid_Lock);
702 read_unlock(&GlobalSMBSeslock);
703 /* 1/8th of sec is more than enough time for them to exit */
704 msleep(125);
707 if (!list_empty(&server->pending_mid_q)) {
708 /* mpx threads have not exited yet give them
709 at least the smb send timeout time for long ops */
710 /* due to delays on oplock break requests, we need
711 to wait at least 45 seconds before giving up
712 on a request getting a response and going ahead
713 and killing cifsd */
714 cFYI(1, ("Wait for exit from demultiplex thread"));
715 msleep(46000);
716 /* if threads still have not exited they are probably never
717 coming home not much else we can do but free the memory */
720 write_lock(&GlobalSMBSeslock);
721 atomic_dec(&tcpSesAllocCount);
722 length = tcpSesAllocCount.counter;
724 /* last chance to mark ses pointers invalid
725 if there are any pointing to this (e.g
726 if a crazy root user tried to kill cifsd
727 kernel thread explicitly this might happen) */
728 list_for_each(tmp, &GlobalSMBSessionList) {
729 ses = list_entry(tmp, struct cifsSesInfo,
730 cifsSessionList);
731 if (ses->server == server) {
732 ses->server = NULL;
735 write_unlock(&GlobalSMBSeslock);
737 kfree(server);
738 if(length > 0) {
739 mempool_resize(cifs_req_poolp,
740 length + cifs_min_rcv,
741 GFP_KERNEL);
744 complete_and_exit(&cifsd_complete, 0);
745 return 0;
748 static int
749 cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
751 char *value;
752 char *data;
753 unsigned int temp_len, i, j;
754 char separator[2];
756 separator[0] = ',';
757 separator[1] = 0;
759 memset(vol->source_rfc1001_name,0x20,15);
760 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
761 /* does not have to be a perfect mapping since the field is
762 informational, only used for servers that do not support
763 port 445 and it can be overridden at mount time */
764 vol->source_rfc1001_name[i] =
765 toupper(system_utsname.nodename[i]);
767 vol->source_rfc1001_name[15] = 0;
768 /* null target name indicates to use *SMBSERVR default called name
769 if we end up sending RFC1001 session initialize */
770 vol->target_rfc1001_name[0] = 0;
771 vol->linux_uid = current->uid; /* current->euid instead? */
772 vol->linux_gid = current->gid;
773 vol->dir_mode = S_IRWXUGO;
774 /* 2767 perms indicate mandatory locking support */
775 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
777 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
778 vol->rw = TRUE;
780 /* default is always to request posix paths. */
781 vol->posix_paths = 1;
783 if (!options)
784 return 1;
786 if(strncmp(options,"sep=",4) == 0) {
787 if(options[4] != 0) {
788 separator[0] = options[4];
789 options += 5;
790 } else {
791 cFYI(1,("Null separator not allowed"));
795 while ((data = strsep(&options, separator)) != NULL) {
796 if (!*data)
797 continue;
798 if ((value = strchr(data, '=')) != NULL)
799 *value++ = '\0';
801 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
802 vol->no_xattr = 0;
803 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
804 vol->no_xattr = 1;
805 } else if (strnicmp(data, "user", 4) == 0) {
806 if (!value || !*value) {
807 printk(KERN_WARNING
808 "CIFS: invalid or missing username\n");
809 return 1; /* needs_arg; */
811 if (strnlen(value, 200) < 200) {
812 vol->username = value;
813 } else {
814 printk(KERN_WARNING "CIFS: username too long\n");
815 return 1;
817 } else if (strnicmp(data, "pass", 4) == 0) {
818 if (!value) {
819 vol->password = NULL;
820 continue;
821 } else if(value[0] == 0) {
822 /* check if string begins with double comma
823 since that would mean the password really
824 does start with a comma, and would not
825 indicate an empty string */
826 if(value[1] != separator[0]) {
827 vol->password = NULL;
828 continue;
831 temp_len = strlen(value);
832 /* removed password length check, NTLM passwords
833 can be arbitrarily long */
835 /* if comma in password, the string will be
836 prematurely null terminated. Commas in password are
837 specified across the cifs mount interface by a double
838 comma ie ,, and a comma used as in other cases ie ','
839 as a parameter delimiter/separator is single and due
840 to the strsep above is temporarily zeroed. */
842 /* NB: password legally can have multiple commas and
843 the only illegal character in a password is null */
845 if ((value[temp_len] == 0) &&
846 (value[temp_len+1] == separator[0])) {
847 /* reinsert comma */
848 value[temp_len] = separator[0];
849 temp_len+=2; /* move after the second comma */
850 while(value[temp_len] != 0) {
851 if (value[temp_len] == separator[0]) {
852 if (value[temp_len+1] ==
853 separator[0]) {
854 /* skip second comma */
855 temp_len++;
856 } else {
857 /* single comma indicating start
858 of next parm */
859 break;
862 temp_len++;
864 if(value[temp_len] == 0) {
865 options = NULL;
866 } else {
867 value[temp_len] = 0;
868 /* point option to start of next parm */
869 options = value + temp_len + 1;
871 /* go from value to value + temp_len condensing
872 double commas to singles. Note that this ends up
873 allocating a few bytes too many, which is ok */
874 vol->password = kzalloc(temp_len, GFP_KERNEL);
875 if(vol->password == NULL) {
876 printk("CIFS: no memory for pass\n");
877 return 1;
879 for(i=0,j=0;i<temp_len;i++,j++) {
880 vol->password[j] = value[i];
881 if(value[i] == separator[0]
882 && value[i+1] == separator[0]) {
883 /* skip second comma */
884 i++;
887 vol->password[j] = 0;
888 } else {
889 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
890 if(vol->password == NULL) {
891 printk("CIFS: no memory for pass\n");
892 return 1;
894 strcpy(vol->password, value);
896 } else if (strnicmp(data, "ip", 2) == 0) {
897 if (!value || !*value) {
898 vol->UNCip = NULL;
899 } else if (strnlen(value, 35) < 35) {
900 vol->UNCip = value;
901 } else {
902 printk(KERN_WARNING "CIFS: ip address too long\n");
903 return 1;
905 } else if ((strnicmp(data, "unc", 3) == 0)
906 || (strnicmp(data, "target", 6) == 0)
907 || (strnicmp(data, "path", 4) == 0)) {
908 if (!value || !*value) {
909 printk(KERN_WARNING
910 "CIFS: invalid path to network resource\n");
911 return 1; /* needs_arg; */
913 if ((temp_len = strnlen(value, 300)) < 300) {
914 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
915 if(vol->UNC == NULL)
916 return 1;
917 strcpy(vol->UNC,value);
918 if (strncmp(vol->UNC, "//", 2) == 0) {
919 vol->UNC[0] = '\\';
920 vol->UNC[1] = '\\';
921 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
922 printk(KERN_WARNING
923 "CIFS: UNC Path does not begin with // or \\\\ \n");
924 return 1;
926 } else {
927 printk(KERN_WARNING "CIFS: UNC name too long\n");
928 return 1;
930 } else if ((strnicmp(data, "domain", 3) == 0)
931 || (strnicmp(data, "workgroup", 5) == 0)) {
932 if (!value || !*value) {
933 printk(KERN_WARNING "CIFS: invalid domain name\n");
934 return 1; /* needs_arg; */
936 /* BB are there cases in which a comma can be valid in
937 a domain name and need special handling? */
938 if (strnlen(value, 65) < 65) {
939 vol->domainname = value;
940 cFYI(1, ("Domain name set"));
941 } else {
942 printk(KERN_WARNING "CIFS: domain name too long\n");
943 return 1;
945 } else if (strnicmp(data, "iocharset", 9) == 0) {
946 if (!value || !*value) {
947 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
948 return 1; /* needs_arg; */
950 if (strnlen(value, 65) < 65) {
951 if(strnicmp(value,"default",7))
952 vol->iocharset = value;
953 /* if iocharset not set load_nls_default used by caller */
954 cFYI(1, ("iocharset set to %s",value));
955 } else {
956 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
957 return 1;
959 } else if (strnicmp(data, "uid", 3) == 0) {
960 if (value && *value) {
961 vol->linux_uid =
962 simple_strtoul(value, &value, 0);
964 } else if (strnicmp(data, "gid", 3) == 0) {
965 if (value && *value) {
966 vol->linux_gid =
967 simple_strtoul(value, &value, 0);
969 } else if (strnicmp(data, "file_mode", 4) == 0) {
970 if (value && *value) {
971 vol->file_mode =
972 simple_strtoul(value, &value, 0);
974 } else if (strnicmp(data, "dir_mode", 4) == 0) {
975 if (value && *value) {
976 vol->dir_mode =
977 simple_strtoul(value, &value, 0);
979 } else if (strnicmp(data, "dirmode", 4) == 0) {
980 if (value && *value) {
981 vol->dir_mode =
982 simple_strtoul(value, &value, 0);
984 } else if (strnicmp(data, "port", 4) == 0) {
985 if (value && *value) {
986 vol->port =
987 simple_strtoul(value, &value, 0);
989 } else if (strnicmp(data, "rsize", 5) == 0) {
990 if (value && *value) {
991 vol->rsize =
992 simple_strtoul(value, &value, 0);
994 } else if (strnicmp(data, "wsize", 5) == 0) {
995 if (value && *value) {
996 vol->wsize =
997 simple_strtoul(value, &value, 0);
999 } else if (strnicmp(data, "sockopt", 5) == 0) {
1000 if (value && *value) {
1001 vol->sockopt =
1002 simple_strtoul(value, &value, 0);
1004 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1005 if (!value || !*value || (*value == ' ')) {
1006 cFYI(1,("invalid (empty) netbiosname specified"));
1007 } else {
1008 memset(vol->source_rfc1001_name,0x20,15);
1009 for(i=0;i<15;i++) {
1010 /* BB are there cases in which a comma can be
1011 valid in this workstation netbios name (and need
1012 special handling)? */
1014 /* We do not uppercase netbiosname for user */
1015 if (value[i]==0)
1016 break;
1017 else
1018 vol->source_rfc1001_name[i] = value[i];
1020 /* The string has 16th byte zero still from
1021 set at top of the function */
1022 if((i==15) && (value[i] != 0))
1023 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1025 } else if (strnicmp(data, "servern", 7) == 0) {
1026 /* servernetbiosname specified override *SMBSERVER */
1027 if (!value || !*value || (*value == ' ')) {
1028 cFYI(1,("empty server netbiosname specified"));
1029 } else {
1030 /* last byte, type, is 0x20 for servr type */
1031 memset(vol->target_rfc1001_name,0x20,16);
1033 for(i=0;i<15;i++) {
1034 /* BB are there cases in which a comma can be
1035 valid in this workstation netbios name (and need
1036 special handling)? */
1038 /* user or mount helper must uppercase netbiosname */
1039 if (value[i]==0)
1040 break;
1041 else
1042 vol->target_rfc1001_name[i] = value[i];
1044 /* The string has 16th byte zero still from
1045 set at top of the function */
1046 if((i==15) && (value[i] != 0))
1047 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
1049 } else if (strnicmp(data, "credentials", 4) == 0) {
1050 /* ignore */
1051 } else if (strnicmp(data, "version", 3) == 0) {
1052 /* ignore */
1053 } else if (strnicmp(data, "guest",5) == 0) {
1054 /* ignore */
1055 } else if (strnicmp(data, "rw", 2) == 0) {
1056 vol->rw = TRUE;
1057 } else if ((strnicmp(data, "suid", 4) == 0) ||
1058 (strnicmp(data, "nosuid", 6) == 0) ||
1059 (strnicmp(data, "exec", 4) == 0) ||
1060 (strnicmp(data, "noexec", 6) == 0) ||
1061 (strnicmp(data, "nodev", 5) == 0) ||
1062 (strnicmp(data, "noauto", 6) == 0) ||
1063 (strnicmp(data, "dev", 3) == 0)) {
1064 /* The mount tool or mount.cifs helper (if present)
1065 uses these opts to set flags, and the flags are read
1066 by the kernel vfs layer before we get here (ie
1067 before read super) so there is no point trying to
1068 parse these options again and set anything and it
1069 is ok to just ignore them */
1070 continue;
1071 } else if (strnicmp(data, "ro", 2) == 0) {
1072 vol->rw = FALSE;
1073 } else if (strnicmp(data, "hard", 4) == 0) {
1074 vol->retry = 1;
1075 } else if (strnicmp(data, "soft", 4) == 0) {
1076 vol->retry = 0;
1077 } else if (strnicmp(data, "perm", 4) == 0) {
1078 vol->noperm = 0;
1079 } else if (strnicmp(data, "noperm", 6) == 0) {
1080 vol->noperm = 1;
1081 } else if (strnicmp(data, "mapchars", 8) == 0) {
1082 vol->remap = 1;
1083 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1084 vol->remap = 0;
1085 } else if (strnicmp(data, "sfu", 3) == 0) {
1086 vol->sfu_emul = 1;
1087 } else if (strnicmp(data, "nosfu", 5) == 0) {
1088 vol->sfu_emul = 0;
1089 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1090 vol->posix_paths = 1;
1091 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1092 vol->posix_paths = 0;
1093 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1094 (strnicmp(data, "ignorecase", 10) == 0)) {
1095 vol->nocase = 1;
1096 } else if (strnicmp(data, "brl", 3) == 0) {
1097 vol->nobrl = 0;
1098 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
1099 (strnicmp(data, "nolock", 6) == 0)) {
1100 vol->nobrl = 1;
1101 /* turn off mandatory locking in mode
1102 if remote locking is turned off since the
1103 local vfs will do advisory */
1104 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1105 vol->file_mode = S_IALLUGO;
1106 } else if (strnicmp(data, "setuids", 7) == 0) {
1107 vol->setuids = 1;
1108 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1109 vol->setuids = 0;
1110 } else if (strnicmp(data, "nohard", 6) == 0) {
1111 vol->retry = 0;
1112 } else if (strnicmp(data, "nosoft", 6) == 0) {
1113 vol->retry = 1;
1114 } else if (strnicmp(data, "nointr", 6) == 0) {
1115 vol->intr = 0;
1116 } else if (strnicmp(data, "intr", 4) == 0) {
1117 vol->intr = 1;
1118 } else if (strnicmp(data, "serverino",7) == 0) {
1119 vol->server_ino = 1;
1120 } else if (strnicmp(data, "noserverino",9) == 0) {
1121 vol->server_ino = 0;
1122 } else if (strnicmp(data, "acl",3) == 0) {
1123 vol->no_psx_acl = 0;
1124 } else if (strnicmp(data, "noacl",5) == 0) {
1125 vol->no_psx_acl = 1;
1126 } else if (strnicmp(data, "direct",6) == 0) {
1127 vol->direct_io = 1;
1128 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1129 vol->direct_io = 1;
1130 } else if (strnicmp(data, "in6_addr",8) == 0) {
1131 if (!value || !*value) {
1132 vol->in6_addr = NULL;
1133 } else if (strnlen(value, 49) == 48) {
1134 vol->in6_addr = value;
1135 } else {
1136 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1137 return 1;
1139 } else if (strnicmp(data, "noac", 4) == 0) {
1140 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1141 } else
1142 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1144 if (vol->UNC == NULL) {
1145 if(devname == NULL) {
1146 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1147 return 1;
1149 if ((temp_len = strnlen(devname, 300)) < 300) {
1150 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1151 if(vol->UNC == NULL)
1152 return 1;
1153 strcpy(vol->UNC,devname);
1154 if (strncmp(vol->UNC, "//", 2) == 0) {
1155 vol->UNC[0] = '\\';
1156 vol->UNC[1] = '\\';
1157 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1158 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1159 return 1;
1161 } else {
1162 printk(KERN_WARNING "CIFS: UNC name too long\n");
1163 return 1;
1166 if(vol->UNCip == NULL)
1167 vol->UNCip = &vol->UNC[2];
1169 return 0;
1172 static struct cifsSesInfo *
1173 cifs_find_tcp_session(struct in_addr * target_ip_addr,
1174 struct in6_addr *target_ip6_addr,
1175 char *userName, struct TCP_Server_Info **psrvTcp)
1177 struct list_head *tmp;
1178 struct cifsSesInfo *ses;
1179 *psrvTcp = NULL;
1180 read_lock(&GlobalSMBSeslock);
1182 list_for_each(tmp, &GlobalSMBSessionList) {
1183 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1184 if (ses->server) {
1185 if((target_ip_addr &&
1186 (ses->server->addr.sockAddr.sin_addr.s_addr
1187 == target_ip_addr->s_addr)) || (target_ip6_addr
1188 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1189 target_ip6_addr,sizeof(*target_ip6_addr)))){
1190 /* BB lock server and tcp session and increment use count here?? */
1191 *psrvTcp = ses->server; /* found a match on the TCP session */
1192 /* BB check if reconnection needed */
1193 if (strncmp
1194 (ses->userName, userName,
1195 MAX_USERNAME_SIZE) == 0){
1196 read_unlock(&GlobalSMBSeslock);
1197 return ses; /* found exact match on both tcp and SMB sessions */
1201 /* else tcp and smb sessions need reconnection */
1203 read_unlock(&GlobalSMBSeslock);
1204 return NULL;
1207 static struct cifsTconInfo *
1208 find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1210 struct list_head *tmp;
1211 struct cifsTconInfo *tcon;
1213 read_lock(&GlobalSMBSeslock);
1214 list_for_each(tmp, &GlobalTreeConnectionList) {
1215 cFYI(1, ("Next tcon - "));
1216 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1217 if (tcon->ses) {
1218 if (tcon->ses->server) {
1219 cFYI(1,
1220 (" old ip addr: %x == new ip %x ?",
1221 tcon->ses->server->addr.sockAddr.sin_addr.
1222 s_addr, new_target_ip_addr));
1223 if (tcon->ses->server->addr.sockAddr.sin_addr.
1224 s_addr == new_target_ip_addr) {
1225 /* BB lock tcon and server and tcp session and increment use count here? */
1226 /* found a match on the TCP session */
1227 /* BB check if reconnection needed */
1228 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1229 tcon->treeName, uncName));
1230 if (strncmp
1231 (tcon->treeName, uncName,
1232 MAX_TREE_SIZE) == 0) {
1233 cFYI(1,
1234 ("Matched UNC, old user: %s == new: %s ?",
1235 tcon->treeName, uncName));
1236 if (strncmp
1237 (tcon->ses->userName,
1238 userName,
1239 MAX_USERNAME_SIZE) == 0) {
1240 read_unlock(&GlobalSMBSeslock);
1241 return tcon;/* also matched user (smb session)*/
1248 read_unlock(&GlobalSMBSeslock);
1249 return NULL;
1253 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1254 const char *old_path, const struct nls_table *nls_codepage,
1255 int remap)
1257 unsigned char *referrals = NULL;
1258 unsigned int num_referrals;
1259 int rc = 0;
1261 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
1262 &num_referrals, &referrals, remap);
1264 /* BB Add in code to: if valid refrl, if not ip address contact
1265 the helper that resolves tcp names, mount to it, try to
1266 tcon to it unmount it if fail */
1268 if(referrals)
1269 kfree(referrals);
1271 return rc;
1275 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1276 const char *old_path, const struct nls_table *nls_codepage,
1277 unsigned int *pnum_referrals,
1278 unsigned char ** preferrals, int remap)
1280 char *temp_unc;
1281 int rc = 0;
1283 *pnum_referrals = 0;
1285 if (pSesInfo->ipc_tid == 0) {
1286 temp_unc = kmalloc(2 /* for slashes */ +
1287 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1288 + 1 + 4 /* slash IPC$ */ + 2,
1289 GFP_KERNEL);
1290 if (temp_unc == NULL)
1291 return -ENOMEM;
1292 temp_unc[0] = '\\';
1293 temp_unc[1] = '\\';
1294 strcpy(temp_unc + 2, pSesInfo->serverName);
1295 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1296 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1297 cFYI(1,
1298 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1299 kfree(temp_unc);
1301 if (rc == 0)
1302 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
1303 pnum_referrals, nls_codepage, remap);
1305 return rc;
1308 /* See RFC1001 section 14 on representation of Netbios names */
1309 static void rfc1002mangle(char * target,char * source, unsigned int length)
1311 unsigned int i,j;
1313 for(i=0,j=0;i<(length);i++) {
1314 /* mask a nibble at a time and encode */
1315 target[j] = 'A' + (0x0F & (source[i] >> 4));
1316 target[j+1] = 'A' + (0x0F & source[i]);
1317 j+=2;
1323 static int
1324 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1325 char * netbios_name, char * target_name)
1327 int rc = 0;
1328 int connected = 0;
1329 __be16 orig_port = 0;
1331 if(*csocket == NULL) {
1332 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1333 if (rc < 0) {
1334 cERROR(1, ("Error %d creating socket",rc));
1335 *csocket = NULL;
1336 return rc;
1337 } else {
1338 /* BB other socket options to set KEEPALIVE, NODELAY? */
1339 cFYI(1,("Socket created"));
1340 (*csocket)->sk->sk_allocation = GFP_NOFS;
1344 psin_server->sin_family = AF_INET;
1345 if(psin_server->sin_port) { /* user overrode default port */
1346 rc = (*csocket)->ops->connect(*csocket,
1347 (struct sockaddr *) psin_server,
1348 sizeof (struct sockaddr_in),0);
1349 if (rc >= 0)
1350 connected = 1;
1353 if(!connected) {
1354 /* save original port so we can retry user specified port
1355 later if fall back ports fail this time */
1356 orig_port = psin_server->sin_port;
1358 /* do not retry on the same port we just failed on */
1359 if(psin_server->sin_port != htons(CIFS_PORT)) {
1360 psin_server->sin_port = htons(CIFS_PORT);
1362 rc = (*csocket)->ops->connect(*csocket,
1363 (struct sockaddr *) psin_server,
1364 sizeof (struct sockaddr_in),0);
1365 if (rc >= 0)
1366 connected = 1;
1369 if (!connected) {
1370 psin_server->sin_port = htons(RFC1001_PORT);
1371 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1372 psin_server, sizeof (struct sockaddr_in),0);
1373 if (rc >= 0)
1374 connected = 1;
1377 /* give up here - unless we want to retry on different
1378 protocol families some day */
1379 if (!connected) {
1380 if(orig_port)
1381 psin_server->sin_port = orig_port;
1382 cFYI(1,("Error %d connecting to server via ipv4",rc));
1383 sock_release(*csocket);
1384 *csocket = NULL;
1385 return rc;
1387 /* Eventually check for other socket options to change from
1388 the default. sock_setsockopt not used because it expects
1389 user space buffer */
1390 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1391 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
1392 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1393 /* make the bufsizes depend on wsize/rsize and max requests */
1394 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1395 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1396 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1397 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
1399 /* send RFC1001 sessinit */
1400 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1401 /* some servers require RFC1001 sessinit before sending
1402 negprot - BB check reconnection in case where second
1403 sessinit is sent but no second negprot */
1404 struct rfc1002_session_packet * ses_init_buf;
1405 struct smb_hdr * smb_buf;
1406 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
1407 if(ses_init_buf) {
1408 ses_init_buf->trailer.session_req.called_len = 32;
1409 if(target_name && (target_name[0] != 0)) {
1410 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1411 target_name, 16);
1412 } else {
1413 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1414 DEFAULT_CIFS_CALLED_NAME,16);
1417 ses_init_buf->trailer.session_req.calling_len = 32;
1418 /* calling name ends in null (byte 16) from old smb
1419 convention. */
1420 if(netbios_name && (netbios_name[0] !=0)) {
1421 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1422 netbios_name,16);
1423 } else {
1424 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1425 "LINUX_CIFS_CLNT",16);
1427 ses_init_buf->trailer.session_req.scope1 = 0;
1428 ses_init_buf->trailer.session_req.scope2 = 0;
1429 smb_buf = (struct smb_hdr *)ses_init_buf;
1430 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1431 smb_buf->smb_buf_length = 0x81000044;
1432 rc = smb_send(*csocket, smb_buf, 0x44,
1433 (struct sockaddr *)psin_server);
1434 kfree(ses_init_buf);
1436 /* else the negprot may still work without this
1437 even though malloc failed */
1441 return rc;
1444 static int
1445 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1447 int rc = 0;
1448 int connected = 0;
1449 __be16 orig_port = 0;
1451 if(*csocket == NULL) {
1452 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1453 if (rc < 0) {
1454 cERROR(1, ("Error %d creating ipv6 socket",rc));
1455 *csocket = NULL;
1456 return rc;
1457 } else {
1458 /* BB other socket options to set KEEPALIVE, NODELAY? */
1459 cFYI(1,("ipv6 Socket created"));
1460 (*csocket)->sk->sk_allocation = GFP_NOFS;
1464 psin_server->sin6_family = AF_INET6;
1466 if(psin_server->sin6_port) { /* user overrode default port */
1467 rc = (*csocket)->ops->connect(*csocket,
1468 (struct sockaddr *) psin_server,
1469 sizeof (struct sockaddr_in6),0);
1470 if (rc >= 0)
1471 connected = 1;
1474 if(!connected) {
1475 /* save original port so we can retry user specified port
1476 later if fall back ports fail this time */
1478 orig_port = psin_server->sin6_port;
1479 /* do not retry on the same port we just failed on */
1480 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1481 psin_server->sin6_port = htons(CIFS_PORT);
1483 rc = (*csocket)->ops->connect(*csocket,
1484 (struct sockaddr *) psin_server,
1485 sizeof (struct sockaddr_in6),0);
1486 if (rc >= 0)
1487 connected = 1;
1490 if (!connected) {
1491 psin_server->sin6_port = htons(RFC1001_PORT);
1492 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1493 psin_server, sizeof (struct sockaddr_in6),0);
1494 if (rc >= 0)
1495 connected = 1;
1498 /* give up here - unless we want to retry on different
1499 protocol families some day */
1500 if (!connected) {
1501 if(orig_port)
1502 psin_server->sin6_port = orig_port;
1503 cFYI(1,("Error %d connecting to server via ipv6",rc));
1504 sock_release(*csocket);
1505 *csocket = NULL;
1506 return rc;
1508 /* Eventually check for other socket options to change from
1509 the default. sock_setsockopt not used because it expects
1510 user space buffer */
1511 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1513 return rc;
1517 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1518 char *mount_data, const char *devname)
1520 int rc = 0;
1521 int xid;
1522 int address_type = AF_INET;
1523 struct socket *csocket = NULL;
1524 struct sockaddr_in sin_server;
1525 struct sockaddr_in6 sin_server6;
1526 struct smb_vol volume_info;
1527 struct cifsSesInfo *pSesInfo = NULL;
1528 struct cifsSesInfo *existingCifsSes = NULL;
1529 struct cifsTconInfo *tcon = NULL;
1530 struct TCP_Server_Info *srvTcp = NULL;
1532 xid = GetXid();
1534 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1536 memset(&volume_info,0,sizeof(struct smb_vol));
1537 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1538 if(volume_info.UNC)
1539 kfree(volume_info.UNC);
1540 if(volume_info.password)
1541 kfree(volume_info.password);
1542 FreeXid(xid);
1543 return -EINVAL;
1546 if (volume_info.username) {
1547 /* BB fixme parse for domain name here */
1548 cFYI(1, ("Username: %s ", volume_info.username));
1550 } else {
1551 cifserror("No username specified ");
1552 /* In userspace mount helper we can get user name from alternate
1553 locations such as env variables and files on disk */
1554 if(volume_info.UNC)
1555 kfree(volume_info.UNC);
1556 if(volume_info.password)
1557 kfree(volume_info.password);
1558 FreeXid(xid);
1559 return -EINVAL;
1562 if (volume_info.UNCip && volume_info.UNC) {
1563 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1565 if(rc <= 0) {
1566 /* not ipv4 address, try ipv6 */
1567 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1568 if(rc > 0)
1569 address_type = AF_INET6;
1570 } else {
1571 address_type = AF_INET;
1574 if(rc <= 0) {
1575 /* we failed translating address */
1576 if(volume_info.UNC)
1577 kfree(volume_info.UNC);
1578 if(volume_info.password)
1579 kfree(volume_info.password);
1580 FreeXid(xid);
1581 return -EINVAL;
1584 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1585 /* success */
1586 rc = 0;
1587 } else if (volume_info.UNCip){
1588 /* BB using ip addr as server name connect to the DFS root below */
1589 cERROR(1,("Connecting to DFS root not implemented yet"));
1590 if(volume_info.UNC)
1591 kfree(volume_info.UNC);
1592 if(volume_info.password)
1593 kfree(volume_info.password);
1594 FreeXid(xid);
1595 return -EINVAL;
1596 } else /* which servers DFS root would we conect to */ {
1597 cERROR(1,
1598 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1599 if(volume_info.UNC)
1600 kfree(volume_info.UNC);
1601 if(volume_info.password)
1602 kfree(volume_info.password);
1603 FreeXid(xid);
1604 return -EINVAL;
1607 /* this is needed for ASCII cp to Unicode converts */
1608 if(volume_info.iocharset == NULL) {
1609 cifs_sb->local_nls = load_nls_default();
1610 /* load_nls_default can not return null */
1611 } else {
1612 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1613 if(cifs_sb->local_nls == NULL) {
1614 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1615 if(volume_info.UNC)
1616 kfree(volume_info.UNC);
1617 if(volume_info.password)
1618 kfree(volume_info.password);
1619 FreeXid(xid);
1620 return -ELIBACC;
1624 if(address_type == AF_INET)
1625 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1626 NULL /* no ipv6 addr */,
1627 volume_info.username, &srvTcp);
1628 else if(address_type == AF_INET6)
1629 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1630 &sin_server6.sin6_addr,
1631 volume_info.username, &srvTcp);
1632 else {
1633 if(volume_info.UNC)
1634 kfree(volume_info.UNC);
1635 if(volume_info.password)
1636 kfree(volume_info.password);
1637 FreeXid(xid);
1638 return -EINVAL;
1642 if (srvTcp) {
1643 cFYI(1, ("Existing tcp session with server found "));
1644 } else { /* create socket */
1645 if(volume_info.port)
1646 sin_server.sin_port = htons(volume_info.port);
1647 else
1648 sin_server.sin_port = 0;
1649 rc = ipv4_connect(&sin_server,&csocket,
1650 volume_info.source_rfc1001_name,
1651 volume_info.target_rfc1001_name);
1652 if (rc < 0) {
1653 cERROR(1,
1654 ("Error connecting to IPv4 socket. Aborting operation"));
1655 if(csocket != NULL)
1656 sock_release(csocket);
1657 if(volume_info.UNC)
1658 kfree(volume_info.UNC);
1659 if(volume_info.password)
1660 kfree(volume_info.password);
1661 FreeXid(xid);
1662 return rc;
1665 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1666 if (srvTcp == NULL) {
1667 rc = -ENOMEM;
1668 sock_release(csocket);
1669 if(volume_info.UNC)
1670 kfree(volume_info.UNC);
1671 if(volume_info.password)
1672 kfree(volume_info.password);
1673 FreeXid(xid);
1674 return rc;
1675 } else {
1676 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1677 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1678 atomic_set(&srvTcp->inFlight,0);
1679 /* BB Add code for ipv6 case too */
1680 srvTcp->ssocket = csocket;
1681 srvTcp->protocolType = IPV4;
1682 init_waitqueue_head(&srvTcp->response_q);
1683 init_waitqueue_head(&srvTcp->request_q);
1684 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1685 /* at this point we are the only ones with the pointer
1686 to the struct since the kernel thread not created yet
1687 so no need to spinlock this init of tcpStatus */
1688 srvTcp->tcpStatus = CifsNew;
1689 init_MUTEX(&srvTcp->tcpSem);
1690 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1691 CLONE_FS | CLONE_FILES | CLONE_VM);
1692 if(rc < 0) {
1693 rc = -ENOMEM;
1694 sock_release(csocket);
1695 if(volume_info.UNC)
1696 kfree(volume_info.UNC);
1697 if(volume_info.password)
1698 kfree(volume_info.password);
1699 FreeXid(xid);
1700 return rc;
1702 wait_for_completion(&cifsd_complete);
1703 rc = 0;
1704 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1705 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
1706 srvTcp->sequence_number = 0;
1710 if (existingCifsSes) {
1711 pSesInfo = existingCifsSes;
1712 cFYI(1, ("Existing smb sess found "));
1713 if(volume_info.password)
1714 kfree(volume_info.password);
1715 /* volume_info.UNC freed at end of function */
1716 } else if (!rc) {
1717 cFYI(1, ("Existing smb sess not found "));
1718 pSesInfo = sesInfoAlloc();
1719 if (pSesInfo == NULL)
1720 rc = -ENOMEM;
1721 else {
1722 pSesInfo->server = srvTcp;
1723 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1724 NIPQUAD(sin_server.sin_addr.s_addr));
1727 if (!rc){
1728 /* volume_info.password freed at unmount */
1729 if (volume_info.password)
1730 pSesInfo->password = volume_info.password;
1731 if (volume_info.username)
1732 strncpy(pSesInfo->userName,
1733 volume_info.username,MAX_USERNAME_SIZE);
1734 if (volume_info.domainname)
1735 strncpy(pSesInfo->domainName,
1736 volume_info.domainname,MAX_USERNAME_SIZE);
1737 pSesInfo->linux_uid = volume_info.linux_uid;
1738 down(&pSesInfo->sesSem);
1739 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1740 up(&pSesInfo->sesSem);
1741 if(!rc)
1742 atomic_inc(&srvTcp->socketUseCount);
1743 } else
1744 if(volume_info.password)
1745 kfree(volume_info.password);
1748 /* search for existing tcon to this server share */
1749 if (!rc) {
1750 if(volume_info.rsize > CIFSMaxBufSize) {
1751 cERROR(1,("rsize %d too large, using MaxBufSize",
1752 volume_info.rsize));
1753 cifs_sb->rsize = CIFSMaxBufSize;
1754 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1755 cifs_sb->rsize = volume_info.rsize;
1756 else /* default */
1757 cifs_sb->rsize = CIFSMaxBufSize;
1759 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1760 cERROR(1,("wsize %d too large using 4096 instead",
1761 volume_info.wsize));
1762 cifs_sb->wsize = 4096;
1763 } else if(volume_info.wsize)
1764 cifs_sb->wsize = volume_info.wsize;
1765 else
1766 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1767 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1768 cifs_sb->rsize = PAGE_CACHE_SIZE;
1769 /* Windows ME does this */
1770 cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
1772 cifs_sb->mnt_uid = volume_info.linux_uid;
1773 cifs_sb->mnt_gid = volume_info.linux_gid;
1774 cifs_sb->mnt_file_mode = volume_info.file_mode;
1775 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1776 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1778 if(volume_info.noperm)
1779 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1780 if(volume_info.setuids)
1781 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1782 if(volume_info.server_ino)
1783 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1784 if(volume_info.remap)
1785 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1786 if(volume_info.no_xattr)
1787 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1788 if(volume_info.sfu_emul)
1789 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
1790 if(volume_info.nobrl)
1791 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
1793 if(volume_info.direct_io) {
1794 cFYI(1,("mounting share using direct i/o"));
1795 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1798 tcon =
1799 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1800 volume_info.username);
1801 if (tcon) {
1802 cFYI(1, ("Found match on UNC path "));
1803 /* we can have only one retry value for a connection
1804 to a share so for resources mounted more than once
1805 to the same server share the last value passed in
1806 for the retry flag is used */
1807 tcon->retry = volume_info.retry;
1808 tcon->nocase = volume_info.nocase;
1809 } else {
1810 tcon = tconInfoAlloc();
1811 if (tcon == NULL)
1812 rc = -ENOMEM;
1813 else {
1814 /* check for null share name ie connect to dfs root */
1816 /* BB check if this works for exactly length three strings */
1817 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1818 && (strchr(volume_info.UNC + 3, '/') ==
1819 NULL)) {
1820 rc = connect_to_dfs_path(xid, pSesInfo,
1821 "", cifs_sb->local_nls,
1822 cifs_sb->mnt_cifs_flags &
1823 CIFS_MOUNT_MAP_SPECIAL_CHR);
1824 if(volume_info.UNC)
1825 kfree(volume_info.UNC);
1826 FreeXid(xid);
1827 return -ENODEV;
1828 } else {
1829 rc = CIFSTCon(xid, pSesInfo,
1830 volume_info.UNC,
1831 tcon, cifs_sb->local_nls);
1832 cFYI(1, ("CIFS Tcon rc = %d", rc));
1834 if (!rc) {
1835 atomic_inc(&pSesInfo->inUse);
1836 tcon->retry = volume_info.retry;
1837 tcon->nocase = volume_info.nocase;
1842 if(pSesInfo) {
1843 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1844 sb->s_maxbytes = (u64) 1 << 63;
1845 } else
1846 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1849 sb->s_time_gran = 100;
1851 /* on error free sesinfo and tcon struct if needed */
1852 if (rc) {
1853 /* if session setup failed, use count is zero but
1854 we still need to free cifsd thread */
1855 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1856 spin_lock(&GlobalMid_Lock);
1857 srvTcp->tcpStatus = CifsExiting;
1858 spin_unlock(&GlobalMid_Lock);
1859 if(srvTcp->tsk) {
1860 send_sig(SIGKILL,srvTcp->tsk,1);
1861 wait_for_completion(&cifsd_complete);
1864 /* If find_unc succeeded then rc == 0 so we can not end */
1865 if (tcon) /* up accidently freeing someone elses tcon struct */
1866 tconInfoFree(tcon);
1867 if (existingCifsSes == NULL) {
1868 if (pSesInfo) {
1869 if ((pSesInfo->server) &&
1870 (pSesInfo->status == CifsGood)) {
1871 int temp_rc;
1872 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1873 /* if the socketUseCount is now zero */
1874 if((temp_rc == -ESHUTDOWN) &&
1875 (pSesInfo->server->tsk)) {
1876 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1877 wait_for_completion(&cifsd_complete);
1879 } else
1880 cFYI(1, ("No session or bad tcon"));
1881 sesInfoFree(pSesInfo);
1882 /* pSesInfo = NULL; */
1885 } else {
1886 atomic_inc(&tcon->useCount);
1887 cifs_sb->tcon = tcon;
1888 tcon->ses = pSesInfo;
1890 /* do not care if following two calls succeed - informational only */
1891 CIFSSMBQFSDeviceInfo(xid, tcon);
1892 CIFSSMBQFSAttributeInfo(xid, tcon);
1893 if (tcon->ses->capabilities & CAP_UNIX) {
1894 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
1895 if(!volume_info.no_psx_acl) {
1896 if(CIFS_UNIX_POSIX_ACL_CAP &
1897 le64_to_cpu(tcon->fsUnixInfo.Capability))
1898 cFYI(1,("server negotiated posix acl support"));
1899 sb->s_flags |= MS_POSIXACL;
1902 /* Try and negotiate POSIX pathnames if we can. */
1903 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1904 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1905 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
1906 cFYI(1,("negotiated posix pathnames support"));
1907 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1908 } else {
1909 cFYI(1,("posix pathnames support requested but not supported"));
1914 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
1915 cifs_sb->wsize = min(cifs_sb->wsize,
1916 (tcon->ses->server->maxBuf -
1917 MAX_CIFS_HDR_SIZE));
1918 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
1919 cifs_sb->rsize = min(cifs_sb->rsize,
1920 (tcon->ses->server->maxBuf -
1921 MAX_CIFS_HDR_SIZE));
1924 /* volume_info.password is freed above when existing session found
1925 (in which case it is not needed anymore) but when new sesion is created
1926 the password ptr is put in the new session structure (in which case the
1927 password will be freed at unmount time) */
1928 if(volume_info.UNC)
1929 kfree(volume_info.UNC);
1930 FreeXid(xid);
1931 return rc;
1934 static int
1935 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1936 char session_key[CIFS_SESSION_KEY_SIZE],
1937 const struct nls_table *nls_codepage)
1939 struct smb_hdr *smb_buffer;
1940 struct smb_hdr *smb_buffer_response;
1941 SESSION_SETUP_ANDX *pSMB;
1942 SESSION_SETUP_ANDX *pSMBr;
1943 char *bcc_ptr;
1944 char *user;
1945 char *domain;
1946 int rc = 0;
1947 int remaining_words = 0;
1948 int bytes_returned = 0;
1949 int len;
1950 __u32 capabilities;
1951 __u16 count;
1953 cFYI(1, ("In sesssetup "));
1954 if(ses == NULL)
1955 return -EINVAL;
1956 user = ses->userName;
1957 domain = ses->domainName;
1958 smb_buffer = cifs_buf_get();
1959 if (smb_buffer == NULL) {
1960 return -ENOMEM;
1962 smb_buffer_response = smb_buffer;
1963 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1965 /* send SMBsessionSetup here */
1966 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1967 NULL /* no tCon exists yet */ , 13 /* wct */ );
1969 smb_buffer->Mid = GetNextMid(ses->server);
1970 pSMB->req_no_secext.AndXCommand = 0xFF;
1971 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1972 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1974 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1975 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1977 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1978 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1979 if (ses->capabilities & CAP_UNICODE) {
1980 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1981 capabilities |= CAP_UNICODE;
1983 if (ses->capabilities & CAP_STATUS32) {
1984 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1985 capabilities |= CAP_STATUS32;
1987 if (ses->capabilities & CAP_DFS) {
1988 smb_buffer->Flags2 |= SMBFLG2_DFS;
1989 capabilities |= CAP_DFS;
1991 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1993 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1994 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1996 pSMB->req_no_secext.CaseSensitivePasswordLength =
1997 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1998 bcc_ptr = pByteArea(smb_buffer);
1999 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
2000 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2001 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
2002 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2004 if (ses->capabilities & CAP_UNICODE) {
2005 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2006 *bcc_ptr = 0;
2007 bcc_ptr++;
2009 if(user == NULL)
2010 bytes_returned = 0; /* skill null user */
2011 else
2012 bytes_returned =
2013 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
2014 nls_codepage);
2015 /* convert number of 16 bit words to bytes */
2016 bcc_ptr += 2 * bytes_returned;
2017 bcc_ptr += 2; /* trailing null */
2018 if (domain == NULL)
2019 bytes_returned =
2020 cifs_strtoUCS((wchar_t *) bcc_ptr,
2021 "CIFS_LINUX_DOM", 32, nls_codepage);
2022 else
2023 bytes_returned =
2024 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2025 nls_codepage);
2026 bcc_ptr += 2 * bytes_returned;
2027 bcc_ptr += 2;
2028 bytes_returned =
2029 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2030 32, nls_codepage);
2031 bcc_ptr += 2 * bytes_returned;
2032 bytes_returned =
2033 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
2034 32, nls_codepage);
2035 bcc_ptr += 2 * bytes_returned;
2036 bcc_ptr += 2;
2037 bytes_returned =
2038 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2039 64, nls_codepage);
2040 bcc_ptr += 2 * bytes_returned;
2041 bcc_ptr += 2;
2042 } else {
2043 if(user != NULL) {
2044 strncpy(bcc_ptr, user, 200);
2045 bcc_ptr += strnlen(user, 200);
2047 *bcc_ptr = 0;
2048 bcc_ptr++;
2049 if (domain == NULL) {
2050 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2051 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2052 } else {
2053 strncpy(bcc_ptr, domain, 64);
2054 bcc_ptr += strnlen(domain, 64);
2055 *bcc_ptr = 0;
2056 bcc_ptr++;
2058 strcpy(bcc_ptr, "Linux version ");
2059 bcc_ptr += strlen("Linux version ");
2060 strcpy(bcc_ptr, system_utsname.release);
2061 bcc_ptr += strlen(system_utsname.release) + 1;
2062 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2063 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2065 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2066 smb_buffer->smb_buf_length += count;
2067 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2069 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2070 &bytes_returned, 1);
2071 if (rc) {
2072 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2073 } else if ((smb_buffer_response->WordCount == 3)
2074 || (smb_buffer_response->WordCount == 4)) {
2075 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2076 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2077 if (action & GUEST_LOGIN)
2078 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2079 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2080 cFYI(1, ("UID = %d ", ses->Suid));
2081 /* response can have either 3 or 4 word count - Samba sends 3 */
2082 bcc_ptr = pByteArea(smb_buffer_response);
2083 if ((pSMBr->resp.hdr.WordCount == 3)
2084 || ((pSMBr->resp.hdr.WordCount == 4)
2085 && (blob_len < pSMBr->resp.ByteCount))) {
2086 if (pSMBr->resp.hdr.WordCount == 4)
2087 bcc_ptr += blob_len;
2089 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2090 if ((long) (bcc_ptr) % 2) {
2091 remaining_words =
2092 (BCC(smb_buffer_response) - 1) /2;
2093 bcc_ptr++; /* Unicode strings must be word aligned */
2094 } else {
2095 remaining_words =
2096 BCC(smb_buffer_response) / 2;
2098 len =
2099 UniStrnlen((wchar_t *) bcc_ptr,
2100 remaining_words - 1);
2101 /* We look for obvious messed up bcc or strings in response so we do not go off
2102 the end since (at least) WIN2K and Windows XP have a major bug in not null
2103 terminating last Unicode string in response */
2104 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
2105 if(ses->serverOS == NULL)
2106 goto sesssetup_nomem;
2107 cifs_strfromUCS_le(ses->serverOS,
2108 (wchar_t *)bcc_ptr, len,nls_codepage);
2109 bcc_ptr += 2 * (len + 1);
2110 remaining_words -= len + 1;
2111 ses->serverOS[2 * len] = 0;
2112 ses->serverOS[1 + (2 * len)] = 0;
2113 if (remaining_words > 0) {
2114 len = UniStrnlen((wchar_t *)bcc_ptr,
2115 remaining_words-1);
2116 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
2117 if(ses->serverNOS == NULL)
2118 goto sesssetup_nomem;
2119 cifs_strfromUCS_le(ses->serverNOS,
2120 (wchar_t *)bcc_ptr,len,nls_codepage);
2121 bcc_ptr += 2 * (len + 1);
2122 ses->serverNOS[2 * len] = 0;
2123 ses->serverNOS[1 + (2 * len)] = 0;
2124 if(strncmp(ses->serverNOS,
2125 "NT LAN Manager 4",16) == 0) {
2126 cFYI(1,("NT4 server"));
2127 ses->flags |= CIFS_SES_NT4;
2129 remaining_words -= len + 1;
2130 if (remaining_words > 0) {
2131 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2132 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2133 ses->serverDomain =
2134 kzalloc(2*(len+1),GFP_KERNEL);
2135 if(ses->serverDomain == NULL)
2136 goto sesssetup_nomem;
2137 cifs_strfromUCS_le(ses->serverDomain,
2138 (wchar_t *)bcc_ptr,len,nls_codepage);
2139 bcc_ptr += 2 * (len + 1);
2140 ses->serverDomain[2*len] = 0;
2141 ses->serverDomain[1+(2*len)] = 0;
2142 } /* else no more room so create dummy domain string */
2143 else
2144 ses->serverDomain =
2145 kzalloc(2, GFP_KERNEL);
2146 } else { /* no room so create dummy domain and NOS string */
2147 /* if these kcallocs fail not much we
2148 can do, but better to not fail the
2149 sesssetup itself */
2150 ses->serverDomain =
2151 kzalloc(2, GFP_KERNEL);
2152 ses->serverNOS =
2153 kzalloc(2, GFP_KERNEL);
2155 } else { /* ASCII */
2156 len = strnlen(bcc_ptr, 1024);
2157 if (((long) bcc_ptr + len) - (long)
2158 pByteArea(smb_buffer_response)
2159 <= BCC(smb_buffer_response)) {
2160 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
2161 if(ses->serverOS == NULL)
2162 goto sesssetup_nomem;
2163 strncpy(ses->serverOS,bcc_ptr, len);
2165 bcc_ptr += len;
2166 bcc_ptr[0] = 0; /* null terminate the string */
2167 bcc_ptr++;
2169 len = strnlen(bcc_ptr, 1024);
2170 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
2171 if(ses->serverNOS == NULL)
2172 goto sesssetup_nomem;
2173 strncpy(ses->serverNOS, bcc_ptr, len);
2174 bcc_ptr += len;
2175 bcc_ptr[0] = 0;
2176 bcc_ptr++;
2178 len = strnlen(bcc_ptr, 1024);
2179 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
2180 if(ses->serverDomain == NULL)
2181 goto sesssetup_nomem;
2182 strncpy(ses->serverDomain, bcc_ptr, len);
2183 bcc_ptr += len;
2184 bcc_ptr[0] = 0;
2185 bcc_ptr++;
2186 } else
2187 cFYI(1,
2188 ("Variable field of length %d extends beyond end of smb ",
2189 len));
2191 } else {
2192 cERROR(1,
2193 (" Security Blob Length extends beyond end of SMB"));
2195 } else {
2196 cERROR(1,
2197 (" Invalid Word count %d: ",
2198 smb_buffer_response->WordCount));
2199 rc = -EIO;
2201 sesssetup_nomem: /* do not return an error on nomem for the info strings,
2202 since that could make reconnection harder, and
2203 reconnection might be needed to free memory */
2204 if (smb_buffer)
2205 cifs_buf_release(smb_buffer);
2207 return rc;
2210 static int
2211 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2212 char *SecurityBlob,int SecurityBlobLength,
2213 const struct nls_table *nls_codepage)
2215 struct smb_hdr *smb_buffer;
2216 struct smb_hdr *smb_buffer_response;
2217 SESSION_SETUP_ANDX *pSMB;
2218 SESSION_SETUP_ANDX *pSMBr;
2219 char *bcc_ptr;
2220 char *user;
2221 char *domain;
2222 int rc = 0;
2223 int remaining_words = 0;
2224 int bytes_returned = 0;
2225 int len;
2226 __u32 capabilities;
2227 __u16 count;
2229 cFYI(1, ("In spnego sesssetup "));
2230 if(ses == NULL)
2231 return -EINVAL;
2232 user = ses->userName;
2233 domain = ses->domainName;
2235 smb_buffer = cifs_buf_get();
2236 if (smb_buffer == NULL) {
2237 return -ENOMEM;
2239 smb_buffer_response = smb_buffer;
2240 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2242 /* send SMBsessionSetup here */
2243 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2244 NULL /* no tCon exists yet */ , 12 /* wct */ );
2246 smb_buffer->Mid = GetNextMid(ses->server);
2247 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2248 pSMB->req.AndXCommand = 0xFF;
2249 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2250 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2252 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2253 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2255 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2256 CAP_EXTENDED_SECURITY;
2257 if (ses->capabilities & CAP_UNICODE) {
2258 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2259 capabilities |= CAP_UNICODE;
2261 if (ses->capabilities & CAP_STATUS32) {
2262 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2263 capabilities |= CAP_STATUS32;
2265 if (ses->capabilities & CAP_DFS) {
2266 smb_buffer->Flags2 |= SMBFLG2_DFS;
2267 capabilities |= CAP_DFS;
2269 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2271 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2272 bcc_ptr = pByteArea(smb_buffer);
2273 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2274 bcc_ptr += SecurityBlobLength;
2276 if (ses->capabilities & CAP_UNICODE) {
2277 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2278 *bcc_ptr = 0;
2279 bcc_ptr++;
2281 bytes_returned =
2282 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2283 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2284 bcc_ptr += 2; /* trailing null */
2285 if (domain == NULL)
2286 bytes_returned =
2287 cifs_strtoUCS((wchar_t *) bcc_ptr,
2288 "CIFS_LINUX_DOM", 32, nls_codepage);
2289 else
2290 bytes_returned =
2291 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2292 nls_codepage);
2293 bcc_ptr += 2 * bytes_returned;
2294 bcc_ptr += 2;
2295 bytes_returned =
2296 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2297 32, nls_codepage);
2298 bcc_ptr += 2 * bytes_returned;
2299 bytes_returned =
2300 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2301 nls_codepage);
2302 bcc_ptr += 2 * bytes_returned;
2303 bcc_ptr += 2;
2304 bytes_returned =
2305 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2306 64, nls_codepage);
2307 bcc_ptr += 2 * bytes_returned;
2308 bcc_ptr += 2;
2309 } else {
2310 strncpy(bcc_ptr, user, 200);
2311 bcc_ptr += strnlen(user, 200);
2312 *bcc_ptr = 0;
2313 bcc_ptr++;
2314 if (domain == NULL) {
2315 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2316 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2317 } else {
2318 strncpy(bcc_ptr, domain, 64);
2319 bcc_ptr += strnlen(domain, 64);
2320 *bcc_ptr = 0;
2321 bcc_ptr++;
2323 strcpy(bcc_ptr, "Linux version ");
2324 bcc_ptr += strlen("Linux version ");
2325 strcpy(bcc_ptr, system_utsname.release);
2326 bcc_ptr += strlen(system_utsname.release) + 1;
2327 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2328 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2330 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2331 smb_buffer->smb_buf_length += count;
2332 pSMB->req.ByteCount = cpu_to_le16(count);
2334 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2335 &bytes_returned, 1);
2336 if (rc) {
2337 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2338 } else if ((smb_buffer_response->WordCount == 3)
2339 || (smb_buffer_response->WordCount == 4)) {
2340 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2341 __u16 blob_len =
2342 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2343 if (action & GUEST_LOGIN)
2344 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2345 if (ses) {
2346 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2347 cFYI(1, ("UID = %d ", ses->Suid));
2348 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2350 /* BB Fix below to make endian neutral !! */
2352 if ((pSMBr->resp.hdr.WordCount == 3)
2353 || ((pSMBr->resp.hdr.WordCount == 4)
2354 && (blob_len <
2355 pSMBr->resp.ByteCount))) {
2356 if (pSMBr->resp.hdr.WordCount == 4) {
2357 bcc_ptr +=
2358 blob_len;
2359 cFYI(1,
2360 ("Security Blob Length %d ",
2361 blob_len));
2364 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2365 if ((long) (bcc_ptr) % 2) {
2366 remaining_words =
2367 (BCC(smb_buffer_response)
2368 - 1) / 2;
2369 bcc_ptr++; /* Unicode strings must be word aligned */
2370 } else {
2371 remaining_words =
2373 (smb_buffer_response) / 2;
2375 len =
2376 UniStrnlen((wchar_t *) bcc_ptr,
2377 remaining_words - 1);
2378 /* We look for obvious messed up bcc or strings in response so we do not go off
2379 the end since (at least) WIN2K and Windows XP have a major bug in not null
2380 terminating last Unicode string in response */
2381 ses->serverOS =
2382 kzalloc(2 * (len + 1), GFP_KERNEL);
2383 cifs_strfromUCS_le(ses->serverOS,
2384 (wchar_t *)
2385 bcc_ptr, len,
2386 nls_codepage);
2387 bcc_ptr += 2 * (len + 1);
2388 remaining_words -= len + 1;
2389 ses->serverOS[2 * len] = 0;
2390 ses->serverOS[1 + (2 * len)] = 0;
2391 if (remaining_words > 0) {
2392 len = UniStrnlen((wchar_t *)bcc_ptr,
2393 remaining_words
2394 - 1);
2395 ses->serverNOS =
2396 kzalloc(2 * (len + 1),
2397 GFP_KERNEL);
2398 cifs_strfromUCS_le(ses->serverNOS,
2399 (wchar_t *)bcc_ptr,
2400 len,
2401 nls_codepage);
2402 bcc_ptr += 2 * (len + 1);
2403 ses->serverNOS[2 * len] = 0;
2404 ses->serverNOS[1 + (2 * len)] = 0;
2405 remaining_words -= len + 1;
2406 if (remaining_words > 0) {
2407 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2408 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2409 ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
2410 cifs_strfromUCS_le(ses->serverDomain,
2411 (wchar_t *)bcc_ptr,
2412 len,
2413 nls_codepage);
2414 bcc_ptr += 2*(len+1);
2415 ses->serverDomain[2*len] = 0;
2416 ses->serverDomain[1+(2*len)] = 0;
2417 } /* else no more room so create dummy domain string */
2418 else
2419 ses->serverDomain =
2420 kzalloc(2,GFP_KERNEL);
2421 } else { /* no room so create dummy domain and NOS string */
2422 ses->serverDomain = kzalloc(2, GFP_KERNEL);
2423 ses->serverNOS = kzalloc(2, GFP_KERNEL);
2425 } else { /* ASCII */
2427 len = strnlen(bcc_ptr, 1024);
2428 if (((long) bcc_ptr + len) - (long)
2429 pByteArea(smb_buffer_response)
2430 <= BCC(smb_buffer_response)) {
2431 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
2432 strncpy(ses->serverOS, bcc_ptr, len);
2434 bcc_ptr += len;
2435 bcc_ptr[0] = 0; /* null terminate the string */
2436 bcc_ptr++;
2438 len = strnlen(bcc_ptr, 1024);
2439 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
2440 strncpy(ses->serverNOS, bcc_ptr, len);
2441 bcc_ptr += len;
2442 bcc_ptr[0] = 0;
2443 bcc_ptr++;
2445 len = strnlen(bcc_ptr, 1024);
2446 ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
2447 strncpy(ses->serverDomain, bcc_ptr, len);
2448 bcc_ptr += len;
2449 bcc_ptr[0] = 0;
2450 bcc_ptr++;
2451 } else
2452 cFYI(1,
2453 ("Variable field of length %d extends beyond end of smb ",
2454 len));
2456 } else {
2457 cERROR(1,
2458 (" Security Blob Length extends beyond end of SMB"));
2460 } else {
2461 cERROR(1, ("No session structure passed in."));
2463 } else {
2464 cERROR(1,
2465 (" Invalid Word count %d: ",
2466 smb_buffer_response->WordCount));
2467 rc = -EIO;
2470 if (smb_buffer)
2471 cifs_buf_release(smb_buffer);
2473 return rc;
2476 static int
2477 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2478 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2479 const struct nls_table *nls_codepage)
2481 struct smb_hdr *smb_buffer;
2482 struct smb_hdr *smb_buffer_response;
2483 SESSION_SETUP_ANDX *pSMB;
2484 SESSION_SETUP_ANDX *pSMBr;
2485 char *bcc_ptr;
2486 char *domain;
2487 int rc = 0;
2488 int remaining_words = 0;
2489 int bytes_returned = 0;
2490 int len;
2491 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2492 PNEGOTIATE_MESSAGE SecurityBlob;
2493 PCHALLENGE_MESSAGE SecurityBlob2;
2494 __u32 negotiate_flags, capabilities;
2495 __u16 count;
2497 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2498 if(ses == NULL)
2499 return -EINVAL;
2500 domain = ses->domainName;
2501 *pNTLMv2_flag = FALSE;
2502 smb_buffer = cifs_buf_get();
2503 if (smb_buffer == NULL) {
2504 return -ENOMEM;
2506 smb_buffer_response = smb_buffer;
2507 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2508 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2510 /* send SMBsessionSetup here */
2511 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2512 NULL /* no tCon exists yet */ , 12 /* wct */ );
2514 smb_buffer->Mid = GetNextMid(ses->server);
2515 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2516 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2518 pSMB->req.AndXCommand = 0xFF;
2519 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2520 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2522 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2523 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2525 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2526 CAP_EXTENDED_SECURITY;
2527 if (ses->capabilities & CAP_UNICODE) {
2528 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2529 capabilities |= CAP_UNICODE;
2531 if (ses->capabilities & CAP_STATUS32) {
2532 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2533 capabilities |= CAP_STATUS32;
2535 if (ses->capabilities & CAP_DFS) {
2536 smb_buffer->Flags2 |= SMBFLG2_DFS;
2537 capabilities |= CAP_DFS;
2539 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2541 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2542 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2543 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2544 SecurityBlob->MessageType = NtLmNegotiate;
2545 negotiate_flags =
2546 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2547 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2548 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2549 if(sign_CIFS_PDUs)
2550 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2551 if(ntlmv2_support)
2552 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2553 /* setup pointers to domain name and workstation name */
2554 bcc_ptr += SecurityBlobLength;
2556 SecurityBlob->WorkstationName.Buffer = 0;
2557 SecurityBlob->WorkstationName.Length = 0;
2558 SecurityBlob->WorkstationName.MaximumLength = 0;
2560 if (domain == NULL) {
2561 SecurityBlob->DomainName.Buffer = 0;
2562 SecurityBlob->DomainName.Length = 0;
2563 SecurityBlob->DomainName.MaximumLength = 0;
2564 } else {
2565 __u16 len;
2566 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2567 strncpy(bcc_ptr, domain, 63);
2568 len = strnlen(domain, 64);
2569 SecurityBlob->DomainName.MaximumLength =
2570 cpu_to_le16(len);
2571 SecurityBlob->DomainName.Buffer =
2572 cpu_to_le32((long) &SecurityBlob->
2573 DomainString -
2574 (long) &SecurityBlob->Signature);
2575 bcc_ptr += len;
2576 SecurityBlobLength += len;
2577 SecurityBlob->DomainName.Length =
2578 cpu_to_le16(len);
2580 if (ses->capabilities & CAP_UNICODE) {
2581 if ((long) bcc_ptr % 2) {
2582 *bcc_ptr = 0;
2583 bcc_ptr++;
2586 bytes_returned =
2587 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2588 32, nls_codepage);
2589 bcc_ptr += 2 * bytes_returned;
2590 bytes_returned =
2591 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2592 nls_codepage);
2593 bcc_ptr += 2 * bytes_returned;
2594 bcc_ptr += 2; /* null terminate Linux version */
2595 bytes_returned =
2596 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2597 64, nls_codepage);
2598 bcc_ptr += 2 * bytes_returned;
2599 *(bcc_ptr + 1) = 0;
2600 *(bcc_ptr + 2) = 0;
2601 bcc_ptr += 2; /* null terminate network opsys string */
2602 *(bcc_ptr + 1) = 0;
2603 *(bcc_ptr + 2) = 0;
2604 bcc_ptr += 2; /* null domain */
2605 } else { /* ASCII */
2606 strcpy(bcc_ptr, "Linux version ");
2607 bcc_ptr += strlen("Linux version ");
2608 strcpy(bcc_ptr, system_utsname.release);
2609 bcc_ptr += strlen(system_utsname.release) + 1;
2610 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2611 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2612 bcc_ptr++; /* empty domain field */
2613 *bcc_ptr = 0;
2615 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2616 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2617 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2618 smb_buffer->smb_buf_length += count;
2619 pSMB->req.ByteCount = cpu_to_le16(count);
2621 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2622 &bytes_returned, 1);
2624 if (smb_buffer_response->Status.CifsError ==
2625 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2626 rc = 0;
2628 if (rc) {
2629 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2630 } else if ((smb_buffer_response->WordCount == 3)
2631 || (smb_buffer_response->WordCount == 4)) {
2632 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2633 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2635 if (action & GUEST_LOGIN)
2636 cFYI(1, (" Guest login"));
2637 /* Do we want to set anything in SesInfo struct when guest login? */
2639 bcc_ptr = pByteArea(smb_buffer_response);
2640 /* response can have either 3 or 4 word count - Samba sends 3 */
2642 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2643 if (SecurityBlob2->MessageType != NtLmChallenge) {
2644 cFYI(1,
2645 ("Unexpected NTLMSSP message type received %d",
2646 SecurityBlob2->MessageType));
2647 } else if (ses) {
2648 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2649 cFYI(1, ("UID = %d ", ses->Suid));
2650 if ((pSMBr->resp.hdr.WordCount == 3)
2651 || ((pSMBr->resp.hdr.WordCount == 4)
2652 && (blob_len <
2653 pSMBr->resp.ByteCount))) {
2655 if (pSMBr->resp.hdr.WordCount == 4) {
2656 bcc_ptr += blob_len;
2657 cFYI(1,
2658 ("Security Blob Length %d ",
2659 blob_len));
2662 cFYI(1, ("NTLMSSP Challenge rcvd "));
2664 memcpy(ses->server->cryptKey,
2665 SecurityBlob2->Challenge,
2666 CIFS_CRYPTO_KEY_SIZE);
2667 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2668 *pNTLMv2_flag = TRUE;
2670 if((SecurityBlob2->NegotiateFlags &
2671 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2672 || (sign_CIFS_PDUs > 1))
2673 ses->server->secMode |=
2674 SECMODE_SIGN_REQUIRED;
2675 if ((SecurityBlob2->NegotiateFlags &
2676 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2677 ses->server->secMode |=
2678 SECMODE_SIGN_ENABLED;
2680 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2681 if ((long) (bcc_ptr) % 2) {
2682 remaining_words =
2683 (BCC(smb_buffer_response)
2684 - 1) / 2;
2685 bcc_ptr++; /* Unicode strings must be word aligned */
2686 } else {
2687 remaining_words =
2689 (smb_buffer_response) / 2;
2691 len =
2692 UniStrnlen((wchar_t *) bcc_ptr,
2693 remaining_words - 1);
2694 /* We look for obvious messed up bcc or strings in response so we do not go off
2695 the end since (at least) WIN2K and Windows XP have a major bug in not null
2696 terminating last Unicode string in response */
2697 ses->serverOS =
2698 kzalloc(2 * (len + 1), GFP_KERNEL);
2699 cifs_strfromUCS_le(ses->serverOS,
2700 (wchar_t *)
2701 bcc_ptr, len,
2702 nls_codepage);
2703 bcc_ptr += 2 * (len + 1);
2704 remaining_words -= len + 1;
2705 ses->serverOS[2 * len] = 0;
2706 ses->serverOS[1 + (2 * len)] = 0;
2707 if (remaining_words > 0) {
2708 len = UniStrnlen((wchar_t *)
2709 bcc_ptr,
2710 remaining_words
2711 - 1);
2712 ses->serverNOS =
2713 kzalloc(2 * (len + 1),
2714 GFP_KERNEL);
2715 cifs_strfromUCS_le(ses->
2716 serverNOS,
2717 (wchar_t *)
2718 bcc_ptr,
2719 len,
2720 nls_codepage);
2721 bcc_ptr += 2 * (len + 1);
2722 ses->serverNOS[2 * len] = 0;
2723 ses->serverNOS[1 +
2724 (2 * len)] = 0;
2725 remaining_words -= len + 1;
2726 if (remaining_words > 0) {
2727 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2728 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2729 ses->serverDomain =
2730 kzalloc(2 *
2731 (len +
2733 GFP_KERNEL);
2734 cifs_strfromUCS_le
2735 (ses->
2736 serverDomain,
2737 (wchar_t *)
2738 bcc_ptr, len,
2739 nls_codepage);
2740 bcc_ptr +=
2741 2 * (len + 1);
2742 ses->
2743 serverDomain[2
2744 * len]
2745 = 0;
2746 ses->
2747 serverDomain[1
2751 len)]
2752 = 0;
2753 } /* else no more room so create dummy domain string */
2754 else
2755 ses->serverDomain =
2756 kzalloc(2,
2757 GFP_KERNEL);
2758 } else { /* no room so create dummy domain and NOS string */
2759 ses->serverDomain =
2760 kzalloc(2, GFP_KERNEL);
2761 ses->serverNOS =
2762 kzalloc(2, GFP_KERNEL);
2764 } else { /* ASCII */
2765 len = strnlen(bcc_ptr, 1024);
2766 if (((long) bcc_ptr + len) - (long)
2767 pByteArea(smb_buffer_response)
2768 <= BCC(smb_buffer_response)) {
2769 ses->serverOS =
2770 kzalloc(len + 1,
2771 GFP_KERNEL);
2772 strncpy(ses->serverOS,
2773 bcc_ptr, len);
2775 bcc_ptr += len;
2776 bcc_ptr[0] = 0; /* null terminate string */
2777 bcc_ptr++;
2779 len = strnlen(bcc_ptr, 1024);
2780 ses->serverNOS =
2781 kzalloc(len + 1,
2782 GFP_KERNEL);
2783 strncpy(ses->serverNOS, bcc_ptr, len);
2784 bcc_ptr += len;
2785 bcc_ptr[0] = 0;
2786 bcc_ptr++;
2788 len = strnlen(bcc_ptr, 1024);
2789 ses->serverDomain =
2790 kzalloc(len + 1,
2791 GFP_KERNEL);
2792 strncpy(ses->serverDomain, bcc_ptr, len);
2793 bcc_ptr += len;
2794 bcc_ptr[0] = 0;
2795 bcc_ptr++;
2796 } else
2797 cFYI(1,
2798 ("Variable field of length %d extends beyond end of smb ",
2799 len));
2801 } else {
2802 cERROR(1,
2803 (" Security Blob Length extends beyond end of SMB"));
2805 } else {
2806 cERROR(1, ("No session structure passed in."));
2808 } else {
2809 cERROR(1,
2810 (" Invalid Word count %d: ",
2811 smb_buffer_response->WordCount));
2812 rc = -EIO;
2815 if (smb_buffer)
2816 cifs_buf_release(smb_buffer);
2818 return rc;
2820 static int
2821 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2822 char *ntlm_session_key, int ntlmv2_flag,
2823 const struct nls_table *nls_codepage)
2825 struct smb_hdr *smb_buffer;
2826 struct smb_hdr *smb_buffer_response;
2827 SESSION_SETUP_ANDX *pSMB;
2828 SESSION_SETUP_ANDX *pSMBr;
2829 char *bcc_ptr;
2830 char *user;
2831 char *domain;
2832 int rc = 0;
2833 int remaining_words = 0;
2834 int bytes_returned = 0;
2835 int len;
2836 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2837 PAUTHENTICATE_MESSAGE SecurityBlob;
2838 __u32 negotiate_flags, capabilities;
2839 __u16 count;
2841 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2842 if(ses == NULL)
2843 return -EINVAL;
2844 user = ses->userName;
2845 domain = ses->domainName;
2846 smb_buffer = cifs_buf_get();
2847 if (smb_buffer == NULL) {
2848 return -ENOMEM;
2850 smb_buffer_response = smb_buffer;
2851 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2852 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2854 /* send SMBsessionSetup here */
2855 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2856 NULL /* no tCon exists yet */ , 12 /* wct */ );
2858 smb_buffer->Mid = GetNextMid(ses->server);
2859 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2860 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2861 pSMB->req.AndXCommand = 0xFF;
2862 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2863 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2865 pSMB->req.hdr.Uid = ses->Suid;
2867 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2868 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2870 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2871 CAP_EXTENDED_SECURITY;
2872 if (ses->capabilities & CAP_UNICODE) {
2873 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2874 capabilities |= CAP_UNICODE;
2876 if (ses->capabilities & CAP_STATUS32) {
2877 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2878 capabilities |= CAP_STATUS32;
2880 if (ses->capabilities & CAP_DFS) {
2881 smb_buffer->Flags2 |= SMBFLG2_DFS;
2882 capabilities |= CAP_DFS;
2884 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2886 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2887 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2888 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2889 SecurityBlob->MessageType = NtLmAuthenticate;
2890 bcc_ptr += SecurityBlobLength;
2891 negotiate_flags =
2892 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2893 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2894 0x80000000 | NTLMSSP_NEGOTIATE_128;
2895 if(sign_CIFS_PDUs)
2896 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2897 if(ntlmv2_flag)
2898 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2900 /* setup pointers to domain name and workstation name */
2902 SecurityBlob->WorkstationName.Buffer = 0;
2903 SecurityBlob->WorkstationName.Length = 0;
2904 SecurityBlob->WorkstationName.MaximumLength = 0;
2905 SecurityBlob->SessionKey.Length = 0;
2906 SecurityBlob->SessionKey.MaximumLength = 0;
2907 SecurityBlob->SessionKey.Buffer = 0;
2909 SecurityBlob->LmChallengeResponse.Length = 0;
2910 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2911 SecurityBlob->LmChallengeResponse.Buffer = 0;
2913 SecurityBlob->NtChallengeResponse.Length =
2914 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2915 SecurityBlob->NtChallengeResponse.MaximumLength =
2916 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2917 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2918 SecurityBlob->NtChallengeResponse.Buffer =
2919 cpu_to_le32(SecurityBlobLength);
2920 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2921 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2923 if (ses->capabilities & CAP_UNICODE) {
2924 if (domain == NULL) {
2925 SecurityBlob->DomainName.Buffer = 0;
2926 SecurityBlob->DomainName.Length = 0;
2927 SecurityBlob->DomainName.MaximumLength = 0;
2928 } else {
2929 __u16 len =
2930 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2931 nls_codepage);
2932 len *= 2;
2933 SecurityBlob->DomainName.MaximumLength =
2934 cpu_to_le16(len);
2935 SecurityBlob->DomainName.Buffer =
2936 cpu_to_le32(SecurityBlobLength);
2937 bcc_ptr += len;
2938 SecurityBlobLength += len;
2939 SecurityBlob->DomainName.Length =
2940 cpu_to_le16(len);
2942 if (user == NULL) {
2943 SecurityBlob->UserName.Buffer = 0;
2944 SecurityBlob->UserName.Length = 0;
2945 SecurityBlob->UserName.MaximumLength = 0;
2946 } else {
2947 __u16 len =
2948 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2949 nls_codepage);
2950 len *= 2;
2951 SecurityBlob->UserName.MaximumLength =
2952 cpu_to_le16(len);
2953 SecurityBlob->UserName.Buffer =
2954 cpu_to_le32(SecurityBlobLength);
2955 bcc_ptr += len;
2956 SecurityBlobLength += len;
2957 SecurityBlob->UserName.Length =
2958 cpu_to_le16(len);
2961 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2962 SecurityBlob->WorkstationName.Length *= 2;
2963 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2964 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2965 bcc_ptr += SecurityBlob->WorkstationName.Length;
2966 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2967 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2969 if ((long) bcc_ptr % 2) {
2970 *bcc_ptr = 0;
2971 bcc_ptr++;
2973 bytes_returned =
2974 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2975 32, nls_codepage);
2976 bcc_ptr += 2 * bytes_returned;
2977 bytes_returned =
2978 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2979 nls_codepage);
2980 bcc_ptr += 2 * bytes_returned;
2981 bcc_ptr += 2; /* null term version string */
2982 bytes_returned =
2983 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2984 64, nls_codepage);
2985 bcc_ptr += 2 * bytes_returned;
2986 *(bcc_ptr + 1) = 0;
2987 *(bcc_ptr + 2) = 0;
2988 bcc_ptr += 2; /* null terminate network opsys string */
2989 *(bcc_ptr + 1) = 0;
2990 *(bcc_ptr + 2) = 0;
2991 bcc_ptr += 2; /* null domain */
2992 } else { /* ASCII */
2993 if (domain == NULL) {
2994 SecurityBlob->DomainName.Buffer = 0;
2995 SecurityBlob->DomainName.Length = 0;
2996 SecurityBlob->DomainName.MaximumLength = 0;
2997 } else {
2998 __u16 len;
2999 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3000 strncpy(bcc_ptr, domain, 63);
3001 len = strnlen(domain, 64);
3002 SecurityBlob->DomainName.MaximumLength =
3003 cpu_to_le16(len);
3004 SecurityBlob->DomainName.Buffer =
3005 cpu_to_le32(SecurityBlobLength);
3006 bcc_ptr += len;
3007 SecurityBlobLength += len;
3008 SecurityBlob->DomainName.Length = cpu_to_le16(len);
3010 if (user == NULL) {
3011 SecurityBlob->UserName.Buffer = 0;
3012 SecurityBlob->UserName.Length = 0;
3013 SecurityBlob->UserName.MaximumLength = 0;
3014 } else {
3015 __u16 len;
3016 strncpy(bcc_ptr, user, 63);
3017 len = strnlen(user, 64);
3018 SecurityBlob->UserName.MaximumLength =
3019 cpu_to_le16(len);
3020 SecurityBlob->UserName.Buffer =
3021 cpu_to_le32(SecurityBlobLength);
3022 bcc_ptr += len;
3023 SecurityBlobLength += len;
3024 SecurityBlob->UserName.Length = cpu_to_le16(len);
3026 /* BB fill in our workstation name if known BB */
3028 strcpy(bcc_ptr, "Linux version ");
3029 bcc_ptr += strlen("Linux version ");
3030 strcpy(bcc_ptr, system_utsname.release);
3031 bcc_ptr += strlen(system_utsname.release) + 1;
3032 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3033 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3034 bcc_ptr++; /* null domain */
3035 *bcc_ptr = 0;
3037 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3038 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3039 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3040 smb_buffer->smb_buf_length += count;
3041 pSMB->req.ByteCount = cpu_to_le16(count);
3043 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3044 &bytes_returned, 1);
3045 if (rc) {
3046 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3047 } else if ((smb_buffer_response->WordCount == 3)
3048 || (smb_buffer_response->WordCount == 4)) {
3049 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3050 __u16 blob_len =
3051 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3052 if (action & GUEST_LOGIN)
3053 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3054 /* if(SecurityBlob2->MessageType != NtLm??){
3055 cFYI("Unexpected message type on auth response is %d "));
3056 } */
3057 if (ses) {
3058 cFYI(1,
3059 ("Does UID on challenge %d match auth response UID %d ",
3060 ses->Suid, smb_buffer_response->Uid));
3061 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3062 bcc_ptr = pByteArea(smb_buffer_response);
3063 /* response can have either 3 or 4 word count - Samba sends 3 */
3064 if ((pSMBr->resp.hdr.WordCount == 3)
3065 || ((pSMBr->resp.hdr.WordCount == 4)
3066 && (blob_len <
3067 pSMBr->resp.ByteCount))) {
3068 if (pSMBr->resp.hdr.WordCount == 4) {
3069 bcc_ptr +=
3070 blob_len;
3071 cFYI(1,
3072 ("Security Blob Length %d ",
3073 blob_len));
3076 cFYI(1,
3077 ("NTLMSSP response to Authenticate "));
3079 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3080 if ((long) (bcc_ptr) % 2) {
3081 remaining_words =
3082 (BCC(smb_buffer_response)
3083 - 1) / 2;
3084 bcc_ptr++; /* Unicode strings must be word aligned */
3085 } else {
3086 remaining_words = BCC(smb_buffer_response) / 2;
3088 len =
3089 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3090 /* We look for obvious messed up bcc or strings in response so we do not go off
3091 the end since (at least) WIN2K and Windows XP have a major bug in not null
3092 terminating last Unicode string in response */
3093 ses->serverOS =
3094 kzalloc(2 * (len + 1), GFP_KERNEL);
3095 cifs_strfromUCS_le(ses->serverOS,
3096 (wchar_t *)
3097 bcc_ptr, len,
3098 nls_codepage);
3099 bcc_ptr += 2 * (len + 1);
3100 remaining_words -= len + 1;
3101 ses->serverOS[2 * len] = 0;
3102 ses->serverOS[1 + (2 * len)] = 0;
3103 if (remaining_words > 0) {
3104 len = UniStrnlen((wchar_t *)
3105 bcc_ptr,
3106 remaining_words
3107 - 1);
3108 ses->serverNOS =
3109 kzalloc(2 * (len + 1),
3110 GFP_KERNEL);
3111 cifs_strfromUCS_le(ses->
3112 serverNOS,
3113 (wchar_t *)
3114 bcc_ptr,
3115 len,
3116 nls_codepage);
3117 bcc_ptr += 2 * (len + 1);
3118 ses->serverNOS[2 * len] = 0;
3119 ses->serverNOS[1+(2*len)] = 0;
3120 remaining_words -= len + 1;
3121 if (remaining_words > 0) {
3122 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3123 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3124 ses->serverDomain =
3125 kzalloc(2 *
3126 (len +
3128 GFP_KERNEL);
3129 cifs_strfromUCS_le
3130 (ses->
3131 serverDomain,
3132 (wchar_t *)
3133 bcc_ptr, len,
3134 nls_codepage);
3135 bcc_ptr +=
3136 2 * (len + 1);
3137 ses->
3138 serverDomain[2
3139 * len]
3140 = 0;
3141 ses->
3142 serverDomain[1
3146 len)]
3147 = 0;
3148 } /* else no more room so create dummy domain string */
3149 else
3150 ses->serverDomain = kzalloc(2,GFP_KERNEL);
3151 } else { /* no room so create dummy domain and NOS string */
3152 ses->serverDomain = kzalloc(2, GFP_KERNEL);
3153 ses->serverNOS = kzalloc(2, GFP_KERNEL);
3155 } else { /* ASCII */
3156 len = strnlen(bcc_ptr, 1024);
3157 if (((long) bcc_ptr + len) -
3158 (long) pByteArea(smb_buffer_response)
3159 <= BCC(smb_buffer_response)) {
3160 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
3161 strncpy(ses->serverOS,bcc_ptr, len);
3163 bcc_ptr += len;
3164 bcc_ptr[0] = 0; /* null terminate the string */
3165 bcc_ptr++;
3167 len = strnlen(bcc_ptr, 1024);
3168 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
3169 strncpy(ses->serverNOS, bcc_ptr, len);
3170 bcc_ptr += len;
3171 bcc_ptr[0] = 0;
3172 bcc_ptr++;
3174 len = strnlen(bcc_ptr, 1024);
3175 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
3176 strncpy(ses->serverDomain, bcc_ptr, len);
3177 bcc_ptr += len;
3178 bcc_ptr[0] = 0;
3179 bcc_ptr++;
3180 } else
3181 cFYI(1,
3182 ("Variable field of length %d extends beyond end of smb ",
3183 len));
3185 } else {
3186 cERROR(1,
3187 (" Security Blob Length extends beyond end of SMB"));
3189 } else {
3190 cERROR(1, ("No session structure passed in."));
3192 } else {
3193 cERROR(1,
3194 (" Invalid Word count %d: ",
3195 smb_buffer_response->WordCount));
3196 rc = -EIO;
3199 if (smb_buffer)
3200 cifs_buf_release(smb_buffer);
3202 return rc;
3206 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3207 const char *tree, struct cifsTconInfo *tcon,
3208 const struct nls_table *nls_codepage)
3210 struct smb_hdr *smb_buffer;
3211 struct smb_hdr *smb_buffer_response;
3212 TCONX_REQ *pSMB;
3213 TCONX_RSP *pSMBr;
3214 unsigned char *bcc_ptr;
3215 int rc = 0;
3216 int length;
3217 __u16 count;
3219 if (ses == NULL)
3220 return -EIO;
3222 smb_buffer = cifs_buf_get();
3223 if (smb_buffer == NULL) {
3224 return -ENOMEM;
3226 smb_buffer_response = smb_buffer;
3228 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3229 NULL /*no tid */ , 4 /*wct */ );
3231 smb_buffer->Mid = GetNextMid(ses->server);
3232 smb_buffer->Uid = ses->Suid;
3233 pSMB = (TCONX_REQ *) smb_buffer;
3234 pSMBr = (TCONX_RSP *) smb_buffer_response;
3236 pSMB->AndXCommand = 0xFF;
3237 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3238 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3239 bcc_ptr = &pSMB->Password[0];
3240 bcc_ptr++; /* skip password */
3242 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3243 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3245 if (ses->capabilities & CAP_STATUS32) {
3246 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3248 if (ses->capabilities & CAP_DFS) {
3249 smb_buffer->Flags2 |= SMBFLG2_DFS;
3251 if (ses->capabilities & CAP_UNICODE) {
3252 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3253 length =
3254 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3255 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3256 bcc_ptr += 2; /* skip trailing null */
3257 } else { /* ASCII */
3259 strcpy(bcc_ptr, tree);
3260 bcc_ptr += strlen(tree) + 1;
3262 strcpy(bcc_ptr, "?????");
3263 bcc_ptr += strlen("?????");
3264 bcc_ptr += 1;
3265 count = bcc_ptr - &pSMB->Password[0];
3266 pSMB->hdr.smb_buf_length += count;
3267 pSMB->ByteCount = cpu_to_le16(count);
3269 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3271 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3272 /* above now done in SendReceive */
3273 if ((rc == 0) && (tcon != NULL)) {
3274 tcon->tidStatus = CifsGood;
3275 tcon->tid = smb_buffer_response->Tid;
3276 bcc_ptr = pByteArea(smb_buffer_response);
3277 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3278 /* skip service field (NB: this field is always ASCII) */
3279 bcc_ptr += length + 1;
3280 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3281 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3282 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3283 if ((bcc_ptr + (2 * length)) -
3284 pByteArea(smb_buffer_response) <=
3285 BCC(smb_buffer_response)) {
3286 if(tcon->nativeFileSystem)
3287 kfree(tcon->nativeFileSystem);
3288 tcon->nativeFileSystem =
3289 kzalloc(length + 2, GFP_KERNEL);
3290 cifs_strfromUCS_le(tcon->nativeFileSystem,
3291 (wchar_t *) bcc_ptr,
3292 length, nls_codepage);
3293 bcc_ptr += 2 * length;
3294 bcc_ptr[0] = 0; /* null terminate the string */
3295 bcc_ptr[1] = 0;
3296 bcc_ptr += 2;
3298 /* else do not bother copying these informational fields */
3299 } else {
3300 length = strnlen(bcc_ptr, 1024);
3301 if ((bcc_ptr + length) -
3302 pByteArea(smb_buffer_response) <=
3303 BCC(smb_buffer_response)) {
3304 if(tcon->nativeFileSystem)
3305 kfree(tcon->nativeFileSystem);
3306 tcon->nativeFileSystem =
3307 kzalloc(length + 1, GFP_KERNEL);
3308 strncpy(tcon->nativeFileSystem, bcc_ptr,
3309 length);
3311 /* else do not bother copying these informational fields */
3313 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3314 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3315 } else if ((rc == 0) && tcon == NULL) {
3316 /* all we need to save for IPC$ connection */
3317 ses->ipc_tid = smb_buffer_response->Tid;
3320 if (smb_buffer)
3321 cifs_buf_release(smb_buffer);
3322 return rc;
3326 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3328 int rc = 0;
3329 int xid;
3330 struct cifsSesInfo *ses = NULL;
3331 struct task_struct *cifsd_task;
3333 xid = GetXid();
3335 if (cifs_sb->tcon) {
3336 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3337 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3338 if (rc == -EBUSY) {
3339 FreeXid(xid);
3340 return 0;
3342 tconInfoFree(cifs_sb->tcon);
3343 if ((ses) && (ses->server)) {
3344 /* save off task so we do not refer to ses later */
3345 cifsd_task = ses->server->tsk;
3346 cFYI(1, ("About to do SMBLogoff "));
3347 rc = CIFSSMBLogoff(xid, ses);
3348 if (rc == -EBUSY) {
3349 FreeXid(xid);
3350 return 0;
3351 } else if (rc == -ESHUTDOWN) {
3352 cFYI(1,("Waking up socket by sending it signal"));
3353 if(cifsd_task) {
3354 send_sig(SIGKILL,cifsd_task,1);
3355 wait_for_completion(&cifsd_complete);
3357 rc = 0;
3358 } /* else - we have an smb session
3359 left on this socket do not kill cifsd */
3360 } else
3361 cFYI(1, ("No session or bad tcon"));
3364 cifs_sb->tcon = NULL;
3365 if (ses)
3366 schedule_timeout_interruptible(msecs_to_jiffies(500));
3367 if (ses)
3368 sesInfoFree(ses);
3370 FreeXid(xid);
3371 return rc; /* BB check if we should always return zero here */
3374 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3375 struct nls_table * nls_info)
3377 int rc = 0;
3378 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3379 int ntlmv2_flag = FALSE;
3380 int first_time = 0;
3382 /* what if server changes its buffer size after dropping the session? */
3383 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3384 rc = CIFSSMBNegotiate(xid, pSesInfo);
3385 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3386 rc = CIFSSMBNegotiate(xid, pSesInfo);
3387 if(rc == -EAGAIN)
3388 rc = -EHOSTDOWN;
3390 if(rc == 0) {
3391 spin_lock(&GlobalMid_Lock);
3392 if(pSesInfo->server->tcpStatus != CifsExiting)
3393 pSesInfo->server->tcpStatus = CifsGood;
3394 else
3395 rc = -EHOSTDOWN;
3396 spin_unlock(&GlobalMid_Lock);
3399 first_time = 1;
3401 if (!rc) {
3402 pSesInfo->capabilities = pSesInfo->server->capabilities;
3403 if(linuxExtEnabled == 0)
3404 pSesInfo->capabilities &= (~CAP_UNIX);
3405 /* pSesInfo->sequence_number = 0;*/
3406 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3407 pSesInfo->server->secMode,
3408 pSesInfo->server->capabilities,
3409 pSesInfo->server->timeZone));
3410 if (extended_security
3411 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3412 && (pSesInfo->server->secType == NTLMSSP)) {
3413 cFYI(1, ("New style sesssetup "));
3414 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3415 NULL /* security blob */,
3416 0 /* blob length */,
3417 nls_info);
3418 } else if (extended_security
3419 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3420 && (pSesInfo->server->secType == RawNTLMSSP)) {
3421 cFYI(1, ("NTLMSSP sesssetup "));
3422 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3423 pSesInfo,
3424 &ntlmv2_flag,
3425 nls_info);
3426 if (!rc) {
3427 if(ntlmv2_flag) {
3428 char * v2_response;
3429 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3430 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3431 nls_info)) {
3432 rc = -ENOMEM;
3433 goto ss_err_exit;
3434 } else
3435 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3436 if(v2_response) {
3437 CalcNTLMv2_response(pSesInfo,v2_response);
3438 /* if(first_time)
3439 cifs_calculate_ntlmv2_mac_key(
3440 pSesInfo->server->mac_signing_key,
3441 response, ntlm_session_key, */
3442 kfree(v2_response);
3443 /* BB Put dummy sig in SessSetup PDU? */
3444 } else {
3445 rc = -ENOMEM;
3446 goto ss_err_exit;
3449 } else {
3450 SMBNTencrypt(pSesInfo->password,
3451 pSesInfo->server->cryptKey,
3452 ntlm_session_key);
3454 if(first_time)
3455 cifs_calculate_mac_key(
3456 pSesInfo->server->mac_signing_key,
3457 ntlm_session_key,
3458 pSesInfo->password);
3460 /* for better security the weaker lanman hash not sent
3461 in AuthSessSetup so we no longer calculate it */
3463 rc = CIFSNTLMSSPAuthSessSetup(xid,
3464 pSesInfo,
3465 ntlm_session_key,
3466 ntlmv2_flag,
3467 nls_info);
3469 } else { /* old style NTLM 0.12 session setup */
3470 SMBNTencrypt(pSesInfo->password,
3471 pSesInfo->server->cryptKey,
3472 ntlm_session_key);
3474 if(first_time)
3475 cifs_calculate_mac_key(
3476 pSesInfo->server->mac_signing_key,
3477 ntlm_session_key, pSesInfo->password);
3479 rc = CIFSSessSetup(xid, pSesInfo,
3480 ntlm_session_key, nls_info);
3482 if (rc) {
3483 cERROR(1,("Send error in SessSetup = %d",rc));
3484 } else {
3485 cFYI(1,("CIFS Session Established successfully"));
3486 pSesInfo->status = CifsGood;
3489 ss_err_exit:
3490 return rc;