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