blob: c467de8576105bdd3bdb4d1983b591be53609b2e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve Frenchb8643e12005-04-28 22:41:07 -07004 * Copyright (C) International Business Machines Corp., 2002,2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/fs.h>
22#include <linux/net.h>
23#include <linux/string.h>
24#include <linux/list.h>
25#include <linux/wait.h>
26#include <linux/ipv6.h>
27#include <linux/pagemap.h>
28#include <linux/ctype.h>
29#include <linux/utsname.h>
30#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070031#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070032#include <linux/completion.h>
Steve French0ae0efa2005-10-10 10:57:19 -070033#include <linux/pagevec.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/uaccess.h>
35#include <asm/processor.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
38#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41#include "cifs_fs_sb.h"
42#include "ntlmssp.h"
43#include "nterr.h"
44#include "rfc1002pdu.h"
Steve Frencha2653eb2005-11-10 15:33:38 -080045#include "cn_cifs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#define CIFS_PORT 445
48#define RFC1001_PORT 139
49
Steve Frenchf1914012005-08-18 09:37:34 -070050static DECLARE_COMPLETION(cifsd_complete);
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
53 unsigned char *p24);
54extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
55 unsigned char *p24);
56
57extern mempool_t *cifs_req_poolp;
58
59struct smb_vol {
60 char *username;
61 char *password;
62 char *domainname;
63 char *UNC;
64 char *UNCip;
65 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
66 char *iocharset; /* local code page for mapping to and from Unicode */
67 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070068 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 uid_t linux_uid;
70 gid_t linux_gid;
71 mode_t file_mode;
72 mode_t dir_mode;
73 unsigned rw:1;
74 unsigned retry:1;
75 unsigned intr:1;
76 unsigned setuids:1;
77 unsigned noperm:1;
78 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
79 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
80 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
81 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070082 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Jeremy Allisonac670552005-06-22 17:26:35 -070083 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
Steve Frenchd7245c22005-07-14 18:25:12 -050084 unsigned sfu_emul:1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -070085 unsigned nocase; /* request case insensitive filenames */
86 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 unsigned int rsize;
88 unsigned int wsize;
89 unsigned int sockopt;
90 unsigned short int port;
91};
92
93static int ipv4_connect(struct sockaddr_in *psin_server,
94 struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -070095 char * netb_name,
96 char * server_netb_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097static int ipv6_connect(struct sockaddr_in6 *psin_server,
98 struct socket **csocket);
99
100
101 /*
102 * cifs tcp session reconnection
103 *
104 * mark tcp session as reconnecting so temporarily locked
105 * mark all smb sessions as reconnecting for tcp session
106 * reconnect tcp session
107 * wake up waiters on reconnection? - (not needed currently)
108 */
109
110int
111cifs_reconnect(struct TCP_Server_Info *server)
112{
113 int rc = 0;
114 struct list_head *tmp;
115 struct cifsSesInfo *ses;
116 struct cifsTconInfo *tcon;
117 struct mid_q_entry * mid_entry;
118
119 spin_lock(&GlobalMid_Lock);
120 if(server->tcpStatus == CifsExiting) {
121 /* the demux thread will exit normally
122 next time through the loop */
123 spin_unlock(&GlobalMid_Lock);
124 return rc;
125 } else
126 server->tcpStatus = CifsNeedReconnect;
127 spin_unlock(&GlobalMid_Lock);
128 server->maxBuf = 0;
129
Steve Frenche4eb2952005-04-28 22:41:09 -0700130 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132 /* before reconnecting the tcp session, mark the smb session (uid)
133 and the tid bad so they are not used until reconnected */
134 read_lock(&GlobalSMBSeslock);
135 list_for_each(tmp, &GlobalSMBSessionList) {
136 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
137 if (ses->server) {
138 if (ses->server == server) {
139 ses->status = CifsNeedReconnect;
140 ses->ipc_tid = 0;
141 }
142 }
143 /* else tcp and smb sessions need reconnection */
144 }
145 list_for_each(tmp, &GlobalTreeConnectionList) {
146 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
147 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
148 tcon->tidStatus = CifsNeedReconnect;
149 }
150 }
151 read_unlock(&GlobalSMBSeslock);
152 /* do not want to be sending data on a socket we are freeing */
153 down(&server->tcpSem);
154 if(server->ssocket) {
155 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
156 server->ssocket->flags));
157 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
158 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
159 server->ssocket->flags));
160 sock_release(server->ssocket);
161 server->ssocket = NULL;
162 }
163
164 spin_lock(&GlobalMid_Lock);
165 list_for_each(tmp, &server->pending_mid_q) {
166 mid_entry = list_entry(tmp, struct
167 mid_q_entry,
168 qhead);
169 if(mid_entry) {
170 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700171 /* Mark other intransit requests as needing
172 retry so we do not immediately mark the
173 session bad again (ie after we reconnect
174 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 mid_entry->midState = MID_RETRY_NEEDED;
176 }
177 }
178 }
179 spin_unlock(&GlobalMid_Lock);
180 up(&server->tcpSem);
181
182 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
183 {
184 if(server->protocolType == IPV6) {
185 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
186 } else {
187 rc = ipv4_connect(&server->addr.sockAddr,
188 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700189 server->workstation_RFC1001_name,
190 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 }
192 if(rc) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700193 cFYI(1,("reconnect error %d",rc));
Steve French0cb766a2005-04-28 22:41:11 -0700194 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 } else {
196 atomic_inc(&tcpSesReconnectCount);
197 spin_lock(&GlobalMid_Lock);
198 if(server->tcpStatus != CifsExiting)
199 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700200 server->sequence_number = 0;
201 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 /* atomic_set(&server->inFlight,0);*/
203 wake_up(&server->response_q);
204 }
205 }
206 return rc;
207}
208
Steve Frenche4eb2952005-04-28 22:41:09 -0700209/*
210 return codes:
211 0 not a transact2, or all data present
212 >0 transact2 with that much data missing
213 -EINVAL = invalid transact2
214
215 */
216static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
217{
218 struct smb_t2_rsp * pSMBt;
219 int total_data_size;
220 int data_in_this_rsp;
221 int remaining;
222
223 if(pSMB->Command != SMB_COM_TRANSACTION2)
224 return 0;
225
226 /* check for plausible wct, bcc and t2 data and parm sizes */
227 /* check for parm and data offset going beyond end of smb */
228 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
229 cFYI(1,("invalid transact2 word count"));
230 return -EINVAL;
231 }
232
233 pSMBt = (struct smb_t2_rsp *)pSMB;
234
235 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
236 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
237
238 remaining = total_data_size - data_in_this_rsp;
239
240 if(remaining == 0)
241 return 0;
242 else if(remaining < 0) {
243 cFYI(1,("total data %d smaller than data in frame %d",
244 total_data_size, data_in_this_rsp));
245 return -EINVAL;
246 } else {
247 cFYI(1,("missing %d bytes from transact2, check next response",
248 remaining));
249 if(total_data_size > maxBufSize) {
250 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
251 total_data_size,maxBufSize));
252 return -EINVAL;
253 }
254 return remaining;
255 }
256}
257
258static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
259{
260 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
261 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
262 int total_data_size;
263 int total_in_buf;
264 int remaining;
265 int total_in_buf2;
266 char * data_area_of_target;
267 char * data_area_of_buf2;
268 __u16 byte_count;
269
270 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
271
272 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
273 cFYI(1,("total data sizes of primary and secondary t2 differ"));
274 }
275
276 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
277
278 remaining = total_data_size - total_in_buf;
279
280 if(remaining < 0)
281 return -EINVAL;
282
283 if(remaining == 0) /* nothing to do, ignore */
284 return 0;
285
286 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
287 if(remaining < total_in_buf2) {
288 cFYI(1,("transact2 2nd response contains too much data"));
289 }
290
291 /* find end of first SMB data area */
292 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
293 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
294 /* validate target area */
295
296 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
297 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
298
299 data_area_of_target += total_in_buf;
300
301 /* copy second buffer into end of first buffer */
302 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
303 total_in_buf += total_in_buf2;
304 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
305 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
306 byte_count += total_in_buf2;
307 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
308
Steve French70ca7342005-09-22 16:32:06 -0700309 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700310 byte_count += total_in_buf2;
311
312 /* BB also add check that we are not beyond maximum buffer size */
313
Steve French70ca7342005-09-22 16:32:06 -0700314 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700315
316 if(remaining == total_in_buf2) {
317 cFYI(1,("found the last secondary response"));
318 return 0; /* we are done */
319 } else /* more responses to go */
320 return 1;
321
322}
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324static int
325cifs_demultiplex_thread(struct TCP_Server_Info *server)
326{
327 int length;
328 unsigned int pdu_length, total_read;
329 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700330 struct smb_hdr *bigbuf = NULL;
331 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 struct msghdr smb_msg;
333 struct kvec iov;
334 struct socket *csocket = server->ssocket;
335 struct list_head *tmp;
336 struct cifsSesInfo *ses;
337 struct task_struct *task_to_wake = NULL;
338 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700339 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700340 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700341 int isMultiRsp;
342 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 daemonize("cifsd");
345 allow_signal(SIGKILL);
346 current->flags |= PF_MEMALLOC;
347 server->tsk = current; /* save process info to wake at shutdown */
348 cFYI(1, ("Demultiplex PID: %d", current->pid));
349 write_lock(&GlobalSMBSeslock);
350 atomic_inc(&tcpSesAllocCount);
351 length = tcpSesAllocCount.counter;
352 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700353 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 if(length > 1) {
355 mempool_resize(cifs_req_poolp,
356 length + cifs_min_rcv,
357 GFP_KERNEL);
358 }
359
360 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700361 if (try_to_freeze())
362 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700363 if (bigbuf == NULL) {
364 bigbuf = cifs_buf_get();
365 if(bigbuf == NULL) {
366 cERROR(1,("No memory for large SMB response"));
367 msleep(3000);
368 /* retry will check if exiting */
369 continue;
370 }
371 } else if(isLargeBuf) {
372 /* we are reusing a dirtry large buf, clear its start */
373 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700375
376 if (smallbuf == NULL) {
377 smallbuf = cifs_small_buf_get();
378 if(smallbuf == NULL) {
379 cERROR(1,("No memory for SMB response"));
380 msleep(1000);
381 /* retry will check if exiting */
382 continue;
383 }
384 /* beginning of smb buffer is cleared in our buf_get */
385 } else /* if existing small buf clear beginning */
386 memset(smallbuf, 0, sizeof (struct smb_hdr));
387
388 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700389 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700390 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 iov.iov_base = smb_buffer;
392 iov.iov_len = 4;
393 smb_msg.msg_control = NULL;
394 smb_msg.msg_controllen = 0;
395 length =
396 kernel_recvmsg(csocket, &smb_msg,
397 &iov, 1, 4, 0 /* BB see socket.h flags */);
398
399 if(server->tcpStatus == CifsExiting) {
400 break;
401 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French57337e42005-04-28 22:41:10 -0700402 cFYI(1,("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 cifs_reconnect(server);
404 cFYI(1,("call to reconnect done"));
405 csocket = server->ssocket;
406 continue;
407 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700408 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 allowing socket to clear and app threads to set
410 tcpStatus CifsNeedReconnect if server hung */
411 continue;
412 } else if (length <= 0) {
413 if(server->tcpStatus == CifsNew) {
Steve French57337e42005-04-28 22:41:10 -0700414 cFYI(1,("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700415 /* some servers kill the TCP session rather than
416 returning an SMB negprot error, in which
417 case reconnecting here is not going to help,
418 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 break;
420 }
421 if(length == -EINTR) {
422 cFYI(1,("cifsd thread killed"));
423 break;
424 }
Steve French57337e42005-04-28 22:41:10 -0700425 cFYI(1,("Reconnect after unexpected peek error %d",
426 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 cifs_reconnect(server);
428 csocket = server->ssocket;
429 wake_up(&server->response_q);
430 continue;
Steve French46810cb2005-04-28 22:41:09 -0700431 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700433 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 length));
435 cifs_reconnect(server);
436 csocket = server->ssocket;
437 wake_up(&server->response_q);
438 continue;
439 }
Steve French67010fb2005-04-28 22:41:09 -0700440
Steve French70ca7342005-09-22 16:32:06 -0700441 /* The right amount was read from socket - 4 bytes */
442 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700443
Steve French70ca7342005-09-22 16:32:06 -0700444 /* the first byte big endian of the length field,
445 is actually not part of the length but the type
446 with the most common, zero, as regular data */
447 temp = *((char *) smb_buffer);
448
449 /* Note that FC 1001 length is big endian on the wire,
450 but we convert it here so it is always manipulated
451 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700452 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700453 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700454
Steve French70ca7342005-09-22 16:32:06 -0700455 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
456
457 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700458 continue;
Steve French70ca7342005-09-22 16:32:06 -0700459 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700460 cFYI(1,("Good RFC 1002 session rsp"));
461 continue;
Steve French70ca7342005-09-22 16:32:06 -0700462 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve French46810cb2005-04-28 22:41:09 -0700463 /* we get this from Windows 98 instead of
464 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700465 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700466 pdu_length));
Steve French46810cb2005-04-28 22:41:09 -0700467 if(server->tcpStatus == CifsNew) {
468 /* if nack on negprot (rather than
469 ret of smb negprot error) reconnecting
470 not going to help, ret error to mount */
471 break;
472 } else {
473 /* give server a second to
474 clean up before reconnect attempt */
475 msleep(1000);
476 /* always try 445 first on reconnect
477 since we get NACK on some if we ever
478 connected to port 139 (the NACK is
479 since we do not begin with RFC1001
480 session initialize frame) */
481 server->addr.sockAddr.sin_port =
482 htons(CIFS_PORT);
483 cifs_reconnect(server);
484 csocket = server->ssocket;
485 wake_up(&server->response_q);
486 continue;
487 }
Steve French70ca7342005-09-22 16:32:06 -0700488 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700489 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700490 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
491 length);
Steve French46810cb2005-04-28 22:41:09 -0700492 cifs_reconnect(server);
493 csocket = server->ssocket;
494 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700495 }
496
497 /* else we have an SMB response */
498 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700499 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700500 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700501 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700502 cifs_reconnect(server);
503 csocket = server->ssocket;
504 wake_up(&server->response_q);
505 continue;
506 }
507
508 /* else length ok */
509 reconnect = 0;
510
511 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
512 isLargeBuf = TRUE;
513 memcpy(bigbuf, smallbuf, 4);
514 smb_buffer = bigbuf;
515 }
516 length = 0;
517 iov.iov_base = 4 + (char *)smb_buffer;
518 iov.iov_len = pdu_length;
519 for (total_read = 0; total_read < pdu_length;
520 total_read += length) {
521 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
522 pdu_length - total_read, 0);
523 if((server->tcpStatus == CifsExiting) ||
524 (length == -EINTR)) {
525 /* then will exit */
526 reconnect = 2;
527 break;
528 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700529 cifs_reconnect(server);
530 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 /* Reconnect wakes up rspns q */
532 /* Now we will reread sock */
533 reconnect = 1;
534 break;
535 } else if ((length == -ERESTARTSYS) ||
536 (length == -EAGAIN)) {
537 msleep(1); /* minimum sleep to prevent looping,
538 allowing socket to clear and app
539 threads to set tcpStatus
540 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700541 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700542 } else if (length <= 0) {
543 cERROR(1,("Received no data, expecting %d",
544 pdu_length - total_read));
545 cifs_reconnect(server);
546 csocket = server->ssocket;
547 reconnect = 1;
548 break;
Steve French46810cb2005-04-28 22:41:09 -0700549 }
550 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 if(reconnect == 2)
552 break;
553 else if(reconnect == 1)
554 continue;
555
556 length += 4; /* account for rfc1002 hdr */
557
558
559 dump_smb(smb_buffer, length);
560 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700561 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700562 continue;
563 }
564
565
566 task_to_wake = NULL;
567 spin_lock(&GlobalMid_Lock);
568 list_for_each(tmp, &server->pending_mid_q) {
569 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
570
571 if ((mid_entry->mid == smb_buffer->Mid) &&
572 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
573 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700574 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
575 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700576 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700577 if(mid_entry->resp_buf) {
578 /* merge response - fix up 1st*/
579 if(coalesce_t2(smb_buffer,
580 mid_entry->resp_buf)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 break;
582 } else {
583 /* all parts received */
584 goto multi_t2_fnd;
585 }
586 } else {
587 if(!isLargeBuf) {
588 cERROR(1,("1st trans2 resp needs bigbuf"));
589 /* BB maybe we can fix this up, switch
590 to already allocated large buffer? */
591 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700592 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700593 mid_entry->resp_buf =
594 smb_buffer;
595 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 bigbuf = NULL;
597 }
598 }
599 break;
600 }
601 mid_entry->resp_buf = smb_buffer;
602 if(isLargeBuf)
603 mid_entry->largeBuf = 1;
604 else
605 mid_entry->largeBuf = 0;
606multi_t2_fnd:
607 task_to_wake = mid_entry->tsk;
608 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700609#ifdef CONFIG_CIFS_STATS2
610 mid_entry->when_received = jiffies;
611#endif
Steve Frenche4eb2952005-04-28 22:41:09 -0700612 break;
613 }
614 }
615 spin_unlock(&GlobalMid_Lock);
616 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700617 /* Was previous buf put in mpx struct for multi-rsp? */
618 if(!isMultiRsp) {
619 /* smb buffer will be freed by user thread */
620 if(isLargeBuf) {
621 bigbuf = NULL;
622 } else
623 smallbuf = NULL;
624 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700625 wake_up_process(task_to_wake);
Steve French57337e42005-04-28 22:41:10 -0700626 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700627 && (isMultiRsp == FALSE)) {
628 cERROR(1, ("No task to wake, unknown frame rcvd!"));
Steve French70ca7342005-09-22 16:32:06 -0700629 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
630 sizeof(struct smb_hdr));
Steve Frenche4eb2952005-04-28 22:41:09 -0700631 }
632 } /* end while !EXITING */
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 spin_lock(&GlobalMid_Lock);
635 server->tcpStatus = CifsExiting;
636 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700637 /* check if we have blocked requests that need to free */
638 /* Note that cifs_max_pending is normally 50, but
639 can be set at module install time to as little as two */
640 if(atomic_read(&server->inFlight) >= cifs_max_pending)
641 atomic_set(&server->inFlight, cifs_max_pending - 1);
642 /* We do not want to set the max_pending too low or we
643 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 spin_unlock(&GlobalMid_Lock);
645 /* Although there should not be any requests blocked on
646 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700647 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 to the same server - they now will see the session is in exit state
649 and get out of SendReceive. */
650 wake_up_all(&server->request_q);
651 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700652 msleep(125);
653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 if(server->ssocket) {
655 sock_release(csocket);
656 server->ssocket = NULL;
657 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700658 /* buffer usuallly freed in free_mid - need to free it here on exit */
659 if (bigbuf != NULL)
660 cifs_buf_release(bigbuf);
661 if (smallbuf != NULL)
662 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 read_lock(&GlobalSMBSeslock);
665 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700666 /* loop through server session structures attached to this and
667 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 list_for_each(tmp, &GlobalSMBSessionList) {
669 ses =
670 list_entry(tmp, struct cifsSesInfo,
671 cifsSessionList);
672 if (ses->server == server) {
673 ses->status = CifsExiting;
674 ses->server = NULL;
675 }
676 }
677 read_unlock(&GlobalSMBSeslock);
678 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700679 /* although we can not zero the server struct pointer yet,
680 since there are active requests which may depnd on them,
681 mark the corresponding SMB sessions as exiting too */
682 list_for_each(tmp, &GlobalSMBSessionList) {
683 ses = list_entry(tmp, struct cifsSesInfo,
684 cifsSessionList);
685 if (ses->server == server) {
686 ses->status = CifsExiting;
687 }
688 }
689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 spin_lock(&GlobalMid_Lock);
691 list_for_each(tmp, &server->pending_mid_q) {
692 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
693 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
694 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700695 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 task_to_wake = mid_entry->tsk;
697 if(task_to_wake) {
698 wake_up_process(task_to_wake);
699 }
700 }
701 }
702 spin_unlock(&GlobalMid_Lock);
703 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700705 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 }
707
Steve Frenchf1914012005-08-18 09:37:34 -0700708 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 /* mpx threads have not exited yet give them
710 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700711 /* due to delays on oplock break requests, we need
712 to wait at least 45 seconds before giving up
713 on a request getting a response and going ahead
714 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700716 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 /* if threads still have not exited they are probably never
718 coming home not much else we can do but free the memory */
719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 write_lock(&GlobalSMBSeslock);
722 atomic_dec(&tcpSesAllocCount);
723 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700724
725 /* last chance to mark ses pointers invalid
726 if there are any pointing to this (e.g
727 if a crazy root user tried to kill cifsd
728 kernel thread explicitly this might happen) */
729 list_for_each(tmp, &GlobalSMBSessionList) {
730 ses = list_entry(tmp, struct cifsSesInfo,
731 cifsSessionList);
732 if (ses->server == server) {
733 ses->server = NULL;
734 }
735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700737
738 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 if(length > 0) {
740 mempool_resize(cifs_req_poolp,
741 length + cifs_min_rcv,
742 GFP_KERNEL);
743 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700744
Steve Frenchf1914012005-08-18 09:37:34 -0700745 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return 0;
747}
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749static int
750cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
751{
752 char *value;
753 char *data;
754 unsigned int temp_len, i, j;
755 char separator[2];
756
757 separator[0] = ',';
758 separator[1] = 0;
759
760 memset(vol->source_rfc1001_name,0x20,15);
761 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
762 /* does not have to be a perfect mapping since the field is
763 informational, only used for servers that do not support
764 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700765 vol->source_rfc1001_name[i] =
766 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 }
768 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700769 /* null target name indicates to use *SMBSERVR default called name
770 if we end up sending RFC1001 session initialize */
771 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 vol->linux_uid = current->uid; /* current->euid instead? */
773 vol->linux_gid = current->gid;
774 vol->dir_mode = S_IRWXUGO;
775 /* 2767 perms indicate mandatory locking support */
776 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
777
778 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
779 vol->rw = TRUE;
780
Jeremy Allisonac670552005-06-22 17:26:35 -0700781 /* default is always to request posix paths. */
782 vol->posix_paths = 1;
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (!options)
785 return 1;
786
787 if(strncmp(options,"sep=",4) == 0) {
788 if(options[4] != 0) {
789 separator[0] = options[4];
790 options += 5;
791 } else {
792 cFYI(1,("Null separator not allowed"));
793 }
794 }
795
796 while ((data = strsep(&options, separator)) != NULL) {
797 if (!*data)
798 continue;
799 if ((value = strchr(data, '=')) != NULL)
800 *value++ = '\0';
801
802 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
803 vol->no_xattr = 0;
804 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
805 vol->no_xattr = 1;
806 } else if (strnicmp(data, "user", 4) == 0) {
807 if (!value || !*value) {
808 printk(KERN_WARNING
809 "CIFS: invalid or missing username\n");
810 return 1; /* needs_arg; */
811 }
812 if (strnlen(value, 200) < 200) {
813 vol->username = value;
814 } else {
815 printk(KERN_WARNING "CIFS: username too long\n");
816 return 1;
817 }
818 } else if (strnicmp(data, "pass", 4) == 0) {
819 if (!value) {
820 vol->password = NULL;
821 continue;
822 } else if(value[0] == 0) {
823 /* check if string begins with double comma
824 since that would mean the password really
825 does start with a comma, and would not
826 indicate an empty string */
827 if(value[1] != separator[0]) {
828 vol->password = NULL;
829 continue;
830 }
831 }
832 temp_len = strlen(value);
833 /* removed password length check, NTLM passwords
834 can be arbitrarily long */
835
836 /* if comma in password, the string will be
837 prematurely null terminated. Commas in password are
838 specified across the cifs mount interface by a double
839 comma ie ,, and a comma used as in other cases ie ','
840 as a parameter delimiter/separator is single and due
841 to the strsep above is temporarily zeroed. */
842
843 /* NB: password legally can have multiple commas and
844 the only illegal character in a password is null */
845
Steve French09d1db52005-04-28 22:41:08 -0700846 if ((value[temp_len] == 0) &&
847 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 /* reinsert comma */
849 value[temp_len] = separator[0];
850 temp_len+=2; /* move after the second comma */
851 while(value[temp_len] != 0) {
852 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700853 if (value[temp_len+1] ==
854 separator[0]) {
855 /* skip second comma */
856 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 } else {
858 /* single comma indicating start
859 of next parm */
860 break;
861 }
862 }
863 temp_len++;
864 }
865 if(value[temp_len] == 0) {
866 options = NULL;
867 } else {
868 value[temp_len] = 0;
869 /* point option to start of next parm */
870 options = value + temp_len + 1;
871 }
872 /* go from value to value + temp_len condensing
873 double commas to singles. Note that this ends up
874 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700875 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700876 if(vol->password == NULL) {
877 printk("CIFS: no memory for pass\n");
878 return 1;
879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 for(i=0,j=0;i<temp_len;i++,j++) {
881 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700882 if(value[i] == separator[0]
883 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 /* skip second comma */
885 i++;
886 }
887 }
888 vol->password[j] = 0;
889 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700890 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700891 if(vol->password == NULL) {
892 printk("CIFS: no memory for pass\n");
893 return 1;
894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 strcpy(vol->password, value);
896 }
897 } else if (strnicmp(data, "ip", 2) == 0) {
898 if (!value || !*value) {
899 vol->UNCip = NULL;
900 } else if (strnlen(value, 35) < 35) {
901 vol->UNCip = value;
902 } else {
903 printk(KERN_WARNING "CIFS: ip address too long\n");
904 return 1;
905 }
906 } else if ((strnicmp(data, "unc", 3) == 0)
907 || (strnicmp(data, "target", 6) == 0)
908 || (strnicmp(data, "path", 4) == 0)) {
909 if (!value || !*value) {
910 printk(KERN_WARNING
911 "CIFS: invalid path to network resource\n");
912 return 1; /* needs_arg; */
913 }
914 if ((temp_len = strnlen(value, 300)) < 300) {
915 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
916 if(vol->UNC == NULL)
917 return 1;
918 strcpy(vol->UNC,value);
919 if (strncmp(vol->UNC, "//", 2) == 0) {
920 vol->UNC[0] = '\\';
921 vol->UNC[1] = '\\';
922 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
923 printk(KERN_WARNING
924 "CIFS: UNC Path does not begin with // or \\\\ \n");
925 return 1;
926 }
927 } else {
928 printk(KERN_WARNING "CIFS: UNC name too long\n");
929 return 1;
930 }
931 } else if ((strnicmp(data, "domain", 3) == 0)
932 || (strnicmp(data, "workgroup", 5) == 0)) {
933 if (!value || !*value) {
934 printk(KERN_WARNING "CIFS: invalid domain name\n");
935 return 1; /* needs_arg; */
936 }
937 /* BB are there cases in which a comma can be valid in
938 a domain name and need special handling? */
939 if (strnlen(value, 65) < 65) {
940 vol->domainname = value;
941 cFYI(1, ("Domain name set"));
942 } else {
943 printk(KERN_WARNING "CIFS: domain name too long\n");
944 return 1;
945 }
946 } else if (strnicmp(data, "iocharset", 9) == 0) {
947 if (!value || !*value) {
948 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
949 return 1; /* needs_arg; */
950 }
951 if (strnlen(value, 65) < 65) {
952 if(strnicmp(value,"default",7))
953 vol->iocharset = value;
954 /* if iocharset not set load_nls_default used by caller */
955 cFYI(1, ("iocharset set to %s",value));
956 } else {
957 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
958 return 1;
959 }
960 } else if (strnicmp(data, "uid", 3) == 0) {
961 if (value && *value) {
962 vol->linux_uid =
963 simple_strtoul(value, &value, 0);
964 }
965 } else if (strnicmp(data, "gid", 3) == 0) {
966 if (value && *value) {
967 vol->linux_gid =
968 simple_strtoul(value, &value, 0);
969 }
970 } else if (strnicmp(data, "file_mode", 4) == 0) {
971 if (value && *value) {
972 vol->file_mode =
973 simple_strtoul(value, &value, 0);
974 }
975 } else if (strnicmp(data, "dir_mode", 4) == 0) {
976 if (value && *value) {
977 vol->dir_mode =
978 simple_strtoul(value, &value, 0);
979 }
980 } else if (strnicmp(data, "dirmode", 4) == 0) {
981 if (value && *value) {
982 vol->dir_mode =
983 simple_strtoul(value, &value, 0);
984 }
985 } else if (strnicmp(data, "port", 4) == 0) {
986 if (value && *value) {
987 vol->port =
988 simple_strtoul(value, &value, 0);
989 }
990 } else if (strnicmp(data, "rsize", 5) == 0) {
991 if (value && *value) {
992 vol->rsize =
993 simple_strtoul(value, &value, 0);
994 }
995 } else if (strnicmp(data, "wsize", 5) == 0) {
996 if (value && *value) {
997 vol->wsize =
998 simple_strtoul(value, &value, 0);
999 }
1000 } else if (strnicmp(data, "sockopt", 5) == 0) {
1001 if (value && *value) {
1002 vol->sockopt =
1003 simple_strtoul(value, &value, 0);
1004 }
1005 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1006 if (!value || !*value || (*value == ' ')) {
1007 cFYI(1,("invalid (empty) netbiosname specified"));
1008 } else {
1009 memset(vol->source_rfc1001_name,0x20,15);
1010 for(i=0;i<15;i++) {
1011 /* BB are there cases in which a comma can be
1012 valid in this workstation netbios name (and need
1013 special handling)? */
1014
1015 /* We do not uppercase netbiosname for user */
1016 if (value[i]==0)
1017 break;
1018 else
1019 vol->source_rfc1001_name[i] = value[i];
1020 }
1021 /* The string has 16th byte zero still from
1022 set at top of the function */
1023 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001024 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1025 }
1026 } else if (strnicmp(data, "servern", 7) == 0) {
1027 /* servernetbiosname specified override *SMBSERVER */
1028 if (!value || !*value || (*value == ' ')) {
1029 cFYI(1,("empty server netbiosname specified"));
1030 } else {
1031 /* last byte, type, is 0x20 for servr type */
1032 memset(vol->target_rfc1001_name,0x20,16);
1033
1034 for(i=0;i<15;i++) {
1035 /* BB are there cases in which a comma can be
1036 valid in this workstation netbios name (and need
1037 special handling)? */
1038
1039 /* user or mount helper must uppercase netbiosname */
1040 if (value[i]==0)
1041 break;
1042 else
1043 vol->target_rfc1001_name[i] = value[i];
1044 }
1045 /* The string has 16th byte zero still from
1046 set at top of the function */
1047 if((i==15) && (value[i] != 0))
1048 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 }
1050 } else if (strnicmp(data, "credentials", 4) == 0) {
1051 /* ignore */
1052 } else if (strnicmp(data, "version", 3) == 0) {
1053 /* ignore */
1054 } else if (strnicmp(data, "guest",5) == 0) {
1055 /* ignore */
1056 } else if (strnicmp(data, "rw", 2) == 0) {
1057 vol->rw = TRUE;
1058 } else if ((strnicmp(data, "suid", 4) == 0) ||
1059 (strnicmp(data, "nosuid", 6) == 0) ||
1060 (strnicmp(data, "exec", 4) == 0) ||
1061 (strnicmp(data, "noexec", 6) == 0) ||
1062 (strnicmp(data, "nodev", 5) == 0) ||
1063 (strnicmp(data, "noauto", 6) == 0) ||
1064 (strnicmp(data, "dev", 3) == 0)) {
1065 /* The mount tool or mount.cifs helper (if present)
1066 uses these opts to set flags, and the flags are read
1067 by the kernel vfs layer before we get here (ie
1068 before read super) so there is no point trying to
1069 parse these options again and set anything and it
1070 is ok to just ignore them */
1071 continue;
1072 } else if (strnicmp(data, "ro", 2) == 0) {
1073 vol->rw = FALSE;
1074 } else if (strnicmp(data, "hard", 4) == 0) {
1075 vol->retry = 1;
1076 } else if (strnicmp(data, "soft", 4) == 0) {
1077 vol->retry = 0;
1078 } else if (strnicmp(data, "perm", 4) == 0) {
1079 vol->noperm = 0;
1080 } else if (strnicmp(data, "noperm", 6) == 0) {
1081 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001082 } else if (strnicmp(data, "mapchars", 8) == 0) {
1083 vol->remap = 1;
1084 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1085 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001086 } else if (strnicmp(data, "sfu", 3) == 0) {
1087 vol->sfu_emul = 1;
1088 } else if (strnicmp(data, "nosfu", 5) == 0) {
1089 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001090 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1091 vol->posix_paths = 1;
1092 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1093 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001094 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1095 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001096 vol->nocase = 1;
1097 } else if (strnicmp(data, "brl", 3) == 0) {
1098 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001099 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001100 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001101 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001102 /* turn off mandatory locking in mode
1103 if remote locking is turned off since the
1104 local vfs will do advisory */
1105 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1106 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 } else if (strnicmp(data, "setuids", 7) == 0) {
1108 vol->setuids = 1;
1109 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1110 vol->setuids = 0;
1111 } else if (strnicmp(data, "nohard", 6) == 0) {
1112 vol->retry = 0;
1113 } else if (strnicmp(data, "nosoft", 6) == 0) {
1114 vol->retry = 1;
1115 } else if (strnicmp(data, "nointr", 6) == 0) {
1116 vol->intr = 0;
1117 } else if (strnicmp(data, "intr", 4) == 0) {
1118 vol->intr = 1;
1119 } else if (strnicmp(data, "serverino",7) == 0) {
1120 vol->server_ino = 1;
1121 } else if (strnicmp(data, "noserverino",9) == 0) {
1122 vol->server_ino = 0;
1123 } else if (strnicmp(data, "acl",3) == 0) {
1124 vol->no_psx_acl = 0;
1125 } else if (strnicmp(data, "noacl",5) == 0) {
1126 vol->no_psx_acl = 1;
1127 } else if (strnicmp(data, "direct",6) == 0) {
1128 vol->direct_io = 1;
1129 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1130 vol->direct_io = 1;
1131 } else if (strnicmp(data, "in6_addr",8) == 0) {
1132 if (!value || !*value) {
1133 vol->in6_addr = NULL;
1134 } else if (strnlen(value, 49) == 48) {
1135 vol->in6_addr = value;
1136 } else {
1137 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1138 return 1;
1139 }
1140 } else if (strnicmp(data, "noac", 4) == 0) {
1141 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1142 } else
1143 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1144 }
1145 if (vol->UNC == NULL) {
1146 if(devname == NULL) {
1147 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1148 return 1;
1149 }
1150 if ((temp_len = strnlen(devname, 300)) < 300) {
1151 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1152 if(vol->UNC == NULL)
1153 return 1;
1154 strcpy(vol->UNC,devname);
1155 if (strncmp(vol->UNC, "//", 2) == 0) {
1156 vol->UNC[0] = '\\';
1157 vol->UNC[1] = '\\';
1158 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1159 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1160 return 1;
1161 }
1162 } else {
1163 printk(KERN_WARNING "CIFS: UNC name too long\n");
1164 return 1;
1165 }
1166 }
1167 if(vol->UNCip == NULL)
1168 vol->UNCip = &vol->UNC[2];
1169
1170 return 0;
1171}
1172
1173static struct cifsSesInfo *
1174cifs_find_tcp_session(struct in_addr * target_ip_addr,
1175 struct in6_addr *target_ip6_addr,
1176 char *userName, struct TCP_Server_Info **psrvTcp)
1177{
1178 struct list_head *tmp;
1179 struct cifsSesInfo *ses;
1180 *psrvTcp = NULL;
1181 read_lock(&GlobalSMBSeslock);
1182
1183 list_for_each(tmp, &GlobalSMBSessionList) {
1184 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1185 if (ses->server) {
1186 if((target_ip_addr &&
1187 (ses->server->addr.sockAddr.sin_addr.s_addr
1188 == target_ip_addr->s_addr)) || (target_ip6_addr
1189 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1190 target_ip6_addr,sizeof(*target_ip6_addr)))){
1191 /* BB lock server and tcp session and increment use count here?? */
1192 *psrvTcp = ses->server; /* found a match on the TCP session */
1193 /* BB check if reconnection needed */
1194 if (strncmp
1195 (ses->userName, userName,
1196 MAX_USERNAME_SIZE) == 0){
1197 read_unlock(&GlobalSMBSeslock);
1198 return ses; /* found exact match on both tcp and SMB sessions */
1199 }
1200 }
1201 }
1202 /* else tcp and smb sessions need reconnection */
1203 }
1204 read_unlock(&GlobalSMBSeslock);
1205 return NULL;
1206}
1207
1208static struct cifsTconInfo *
1209find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1210{
1211 struct list_head *tmp;
1212 struct cifsTconInfo *tcon;
1213
1214 read_lock(&GlobalSMBSeslock);
1215 list_for_each(tmp, &GlobalTreeConnectionList) {
1216 cFYI(1, ("Next tcon - "));
1217 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1218 if (tcon->ses) {
1219 if (tcon->ses->server) {
1220 cFYI(1,
1221 (" old ip addr: %x == new ip %x ?",
1222 tcon->ses->server->addr.sockAddr.sin_addr.
1223 s_addr, new_target_ip_addr));
1224 if (tcon->ses->server->addr.sockAddr.sin_addr.
1225 s_addr == new_target_ip_addr) {
1226 /* BB lock tcon and server and tcp session and increment use count here? */
1227 /* found a match on the TCP session */
1228 /* BB check if reconnection needed */
1229 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1230 tcon->treeName, uncName));
1231 if (strncmp
1232 (tcon->treeName, uncName,
1233 MAX_TREE_SIZE) == 0) {
1234 cFYI(1,
1235 ("Matched UNC, old user: %s == new: %s ?",
1236 tcon->treeName, uncName));
1237 if (strncmp
1238 (tcon->ses->userName,
1239 userName,
1240 MAX_USERNAME_SIZE) == 0) {
1241 read_unlock(&GlobalSMBSeslock);
1242 return tcon;/* also matched user (smb session)*/
1243 }
1244 }
1245 }
1246 }
1247 }
1248 }
1249 read_unlock(&GlobalSMBSeslock);
1250 return NULL;
1251}
1252
1253int
1254connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001255 const char *old_path, const struct nls_table *nls_codepage,
1256 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
1258 unsigned char *referrals = NULL;
1259 unsigned int num_referrals;
1260 int rc = 0;
1261
1262 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001263 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265 /* BB Add in code to: if valid refrl, if not ip address contact
1266 the helper that resolves tcp names, mount to it, try to
1267 tcon to it unmount it if fail */
1268
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001269 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
1271 return rc;
1272}
1273
1274int
1275get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1276 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001277 unsigned int *pnum_referrals,
1278 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
1280 char *temp_unc;
1281 int rc = 0;
1282
1283 *pnum_referrals = 0;
1284
1285 if (pSesInfo->ipc_tid == 0) {
1286 temp_unc = kmalloc(2 /* for slashes */ +
1287 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1288 + 1 + 4 /* slash IPC$ */ + 2,
1289 GFP_KERNEL);
1290 if (temp_unc == NULL)
1291 return -ENOMEM;
1292 temp_unc[0] = '\\';
1293 temp_unc[1] = '\\';
1294 strcpy(temp_unc + 2, pSesInfo->serverName);
1295 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1296 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1297 cFYI(1,
1298 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1299 kfree(temp_unc);
1300 }
1301 if (rc == 0)
1302 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001303 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
1305 return rc;
1306}
1307
1308/* See RFC1001 section 14 on representation of Netbios names */
1309static void rfc1002mangle(char * target,char * source, unsigned int length)
1310{
1311 unsigned int i,j;
1312
1313 for(i=0,j=0;i<(length);i++) {
1314 /* mask a nibble at a time and encode */
1315 target[j] = 'A' + (0x0F & (source[i] >> 4));
1316 target[j+1] = 'A' + (0x0F & source[i]);
1317 j+=2;
1318 }
1319
1320}
1321
1322
1323static int
1324ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001325 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
1327 int rc = 0;
1328 int connected = 0;
1329 __be16 orig_port = 0;
1330
1331 if(*csocket == NULL) {
1332 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1333 if (rc < 0) {
1334 cERROR(1, ("Error %d creating socket",rc));
1335 *csocket = NULL;
1336 return rc;
1337 } else {
1338 /* BB other socket options to set KEEPALIVE, NODELAY? */
1339 cFYI(1,("Socket created"));
1340 (*csocket)->sk->sk_allocation = GFP_NOFS;
1341 }
1342 }
1343
1344 psin_server->sin_family = AF_INET;
1345 if(psin_server->sin_port) { /* user overrode default port */
1346 rc = (*csocket)->ops->connect(*csocket,
1347 (struct sockaddr *) psin_server,
1348 sizeof (struct sockaddr_in),0);
1349 if (rc >= 0)
1350 connected = 1;
1351 }
1352
1353 if(!connected) {
1354 /* save original port so we can retry user specified port
1355 later if fall back ports fail this time */
1356 orig_port = psin_server->sin_port;
1357
1358 /* do not retry on the same port we just failed on */
1359 if(psin_server->sin_port != htons(CIFS_PORT)) {
1360 psin_server->sin_port = htons(CIFS_PORT);
1361
1362 rc = (*csocket)->ops->connect(*csocket,
1363 (struct sockaddr *) psin_server,
1364 sizeof (struct sockaddr_in),0);
1365 if (rc >= 0)
1366 connected = 1;
1367 }
1368 }
1369 if (!connected) {
1370 psin_server->sin_port = htons(RFC1001_PORT);
1371 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1372 psin_server, sizeof (struct sockaddr_in),0);
1373 if (rc >= 0)
1374 connected = 1;
1375 }
1376
1377 /* give up here - unless we want to retry on different
1378 protocol families some day */
1379 if (!connected) {
1380 if(orig_port)
1381 psin_server->sin_port = orig_port;
1382 cFYI(1,("Error %d connecting to server via ipv4",rc));
1383 sock_release(*csocket);
1384 *csocket = NULL;
1385 return rc;
1386 }
1387 /* Eventually check for other socket options to change from
1388 the default. sock_setsockopt not used because it expects
1389 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001390 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1391 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001393 /* make the bufsizes depend on wsize/rsize and max requests */
1394 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1395 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1396 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1397 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1401 /* some servers require RFC1001 sessinit before sending
1402 negprot - BB check reconnection in case where second
1403 sessinit is sent but no second negprot */
1404 struct rfc1002_session_packet * ses_init_buf;
1405 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001406 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if(ses_init_buf) {
1408 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001409 if(target_name && (target_name[0] != 0)) {
1410 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1411 target_name, 16);
1412 } else {
1413 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1414 DEFAULT_CIFS_CALLED_NAME,16);
1415 }
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 ses_init_buf->trailer.session_req.calling_len = 32;
1418 /* calling name ends in null (byte 16) from old smb
1419 convention. */
1420 if(netbios_name && (netbios_name[0] !=0)) {
1421 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1422 netbios_name,16);
1423 } else {
1424 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1425 "LINUX_CIFS_CLNT",16);
1426 }
1427 ses_init_buf->trailer.session_req.scope1 = 0;
1428 ses_init_buf->trailer.session_req.scope2 = 0;
1429 smb_buf = (struct smb_hdr *)ses_init_buf;
1430 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1431 smb_buf->smb_buf_length = 0x81000044;
1432 rc = smb_send(*csocket, smb_buf, 0x44,
1433 (struct sockaddr *)psin_server);
1434 kfree(ses_init_buf);
1435 }
1436 /* else the negprot may still work without this
1437 even though malloc failed */
1438
1439 }
1440
1441 return rc;
1442}
1443
1444static int
1445ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1446{
1447 int rc = 0;
1448 int connected = 0;
1449 __be16 orig_port = 0;
1450
1451 if(*csocket == NULL) {
1452 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1453 if (rc < 0) {
1454 cERROR(1, ("Error %d creating ipv6 socket",rc));
1455 *csocket = NULL;
1456 return rc;
1457 } else {
1458 /* BB other socket options to set KEEPALIVE, NODELAY? */
1459 cFYI(1,("ipv6 Socket created"));
1460 (*csocket)->sk->sk_allocation = GFP_NOFS;
1461 }
1462 }
1463
1464 psin_server->sin6_family = AF_INET6;
1465
1466 if(psin_server->sin6_port) { /* user overrode default port */
1467 rc = (*csocket)->ops->connect(*csocket,
1468 (struct sockaddr *) psin_server,
1469 sizeof (struct sockaddr_in6),0);
1470 if (rc >= 0)
1471 connected = 1;
1472 }
1473
1474 if(!connected) {
1475 /* save original port so we can retry user specified port
1476 later if fall back ports fail this time */
1477
1478 orig_port = psin_server->sin6_port;
1479 /* do not retry on the same port we just failed on */
1480 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1481 psin_server->sin6_port = htons(CIFS_PORT);
1482
1483 rc = (*csocket)->ops->connect(*csocket,
1484 (struct sockaddr *) psin_server,
1485 sizeof (struct sockaddr_in6),0);
1486 if (rc >= 0)
1487 connected = 1;
1488 }
1489 }
1490 if (!connected) {
1491 psin_server->sin6_port = htons(RFC1001_PORT);
1492 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1493 psin_server, sizeof (struct sockaddr_in6),0);
1494 if (rc >= 0)
1495 connected = 1;
1496 }
1497
1498 /* give up here - unless we want to retry on different
1499 protocol families some day */
1500 if (!connected) {
1501 if(orig_port)
1502 psin_server->sin6_port = orig_port;
1503 cFYI(1,("Error %d connecting to server via ipv6",rc));
1504 sock_release(*csocket);
1505 *csocket = NULL;
1506 return rc;
1507 }
1508 /* Eventually check for other socket options to change from
1509 the default. sock_setsockopt not used because it expects
1510 user space buffer */
1511 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1512
1513 return rc;
1514}
1515
1516int
1517cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1518 char *mount_data, const char *devname)
1519{
1520 int rc = 0;
1521 int xid;
1522 int address_type = AF_INET;
1523 struct socket *csocket = NULL;
1524 struct sockaddr_in sin_server;
1525 struct sockaddr_in6 sin_server6;
1526 struct smb_vol volume_info;
1527 struct cifsSesInfo *pSesInfo = NULL;
1528 struct cifsSesInfo *existingCifsSes = NULL;
1529 struct cifsTconInfo *tcon = NULL;
1530 struct TCP_Server_Info *srvTcp = NULL;
1531
1532 xid = GetXid();
1533
1534/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1535
1536 memset(&volume_info,0,sizeof(struct smb_vol));
1537 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001538 kfree(volume_info.UNC);
1539 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 FreeXid(xid);
1541 return -EINVAL;
1542 }
1543
1544 if (volume_info.username) {
1545 /* BB fixme parse for domain name here */
1546 cFYI(1, ("Username: %s ", volume_info.username));
1547
1548 } else {
1549 cifserror("No username specified ");
1550 /* In userspace mount helper we can get user name from alternate
1551 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001552 kfree(volume_info.UNC);
1553 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 FreeXid(xid);
1555 return -EINVAL;
1556 }
1557
1558 if (volume_info.UNCip && volume_info.UNC) {
1559 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1560
1561 if(rc <= 0) {
1562 /* not ipv4 address, try ipv6 */
1563 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1564 if(rc > 0)
1565 address_type = AF_INET6;
1566 } else {
1567 address_type = AF_INET;
1568 }
1569
1570 if(rc <= 0) {
1571 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001572 kfree(volume_info.UNC);
1573 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 FreeXid(xid);
1575 return -EINVAL;
1576 }
1577
1578 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1579 /* success */
1580 rc = 0;
1581 } else if (volume_info.UNCip){
1582 /* BB using ip addr as server name connect to the DFS root below */
1583 cERROR(1,("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001584 kfree(volume_info.UNC);
1585 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 FreeXid(xid);
1587 return -EINVAL;
1588 } else /* which servers DFS root would we conect to */ {
1589 cERROR(1,
1590 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001591 kfree(volume_info.UNC);
1592 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 FreeXid(xid);
1594 return -EINVAL;
1595 }
1596
1597 /* this is needed for ASCII cp to Unicode converts */
1598 if(volume_info.iocharset == NULL) {
1599 cifs_sb->local_nls = load_nls_default();
1600 /* load_nls_default can not return null */
1601 } else {
1602 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1603 if(cifs_sb->local_nls == NULL) {
1604 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001605 kfree(volume_info.UNC);
1606 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 FreeXid(xid);
1608 return -ELIBACC;
1609 }
1610 }
1611
1612 if(address_type == AF_INET)
1613 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1614 NULL /* no ipv6 addr */,
1615 volume_info.username, &srvTcp);
1616 else if(address_type == AF_INET6)
1617 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1618 &sin_server6.sin6_addr,
1619 volume_info.username, &srvTcp);
1620 else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001621 kfree(volume_info.UNC);
1622 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 FreeXid(xid);
1624 return -EINVAL;
1625 }
1626
1627
1628 if (srvTcp) {
1629 cFYI(1, ("Existing tcp session with server found "));
1630 } else { /* create socket */
1631 if(volume_info.port)
1632 sin_server.sin_port = htons(volume_info.port);
1633 else
1634 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001635 rc = ipv4_connect(&sin_server,&csocket,
1636 volume_info.source_rfc1001_name,
1637 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (rc < 0) {
1639 cERROR(1,
1640 ("Error connecting to IPv4 socket. Aborting operation"));
1641 if(csocket != NULL)
1642 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001643 kfree(volume_info.UNC);
1644 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 FreeXid(xid);
1646 return rc;
1647 }
1648
1649 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1650 if (srvTcp == NULL) {
1651 rc = -ENOMEM;
1652 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001653 kfree(volume_info.UNC);
1654 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 FreeXid(xid);
1656 return rc;
1657 } else {
1658 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1659 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1660 atomic_set(&srvTcp->inFlight,0);
1661 /* BB Add code for ipv6 case too */
1662 srvTcp->ssocket = csocket;
1663 srvTcp->protocolType = IPV4;
1664 init_waitqueue_head(&srvTcp->response_q);
1665 init_waitqueue_head(&srvTcp->request_q);
1666 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1667 /* at this point we are the only ones with the pointer
1668 to the struct since the kernel thread not created yet
1669 so no need to spinlock this init of tcpStatus */
1670 srvTcp->tcpStatus = CifsNew;
1671 init_MUTEX(&srvTcp->tcpSem);
1672 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1673 CLONE_FS | CLONE_FILES | CLONE_VM);
1674 if(rc < 0) {
1675 rc = -ENOMEM;
1676 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001677 kfree(volume_info.UNC);
1678 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 FreeXid(xid);
1680 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001681 }
1682 wait_for_completion(&cifsd_complete);
1683 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001685 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001686 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 }
1688 }
1689
1690 if (existingCifsSes) {
1691 pSesInfo = existingCifsSes;
1692 cFYI(1, ("Existing smb sess found "));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001693 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 /* volume_info.UNC freed at end of function */
1695 } else if (!rc) {
1696 cFYI(1, ("Existing smb sess not found "));
1697 pSesInfo = sesInfoAlloc();
1698 if (pSesInfo == NULL)
1699 rc = -ENOMEM;
1700 else {
1701 pSesInfo->server = srvTcp;
1702 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1703 NIPQUAD(sin_server.sin_addr.s_addr));
1704 }
1705
1706 if (!rc){
1707 /* volume_info.password freed at unmount */
1708 if (volume_info.password)
1709 pSesInfo->password = volume_info.password;
1710 if (volume_info.username)
1711 strncpy(pSesInfo->userName,
1712 volume_info.username,MAX_USERNAME_SIZE);
1713 if (volume_info.domainname)
1714 strncpy(pSesInfo->domainName,
1715 volume_info.domainname,MAX_USERNAME_SIZE);
1716 pSesInfo->linux_uid = volume_info.linux_uid;
1717 down(&pSesInfo->sesSem);
1718 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1719 up(&pSesInfo->sesSem);
1720 if(!rc)
1721 atomic_inc(&srvTcp->socketUseCount);
1722 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001723 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 }
1725
1726 /* search for existing tcon to this server share */
1727 if (!rc) {
Steve French0ae0efa2005-10-10 10:57:19 -07001728 if(volume_info.rsize > CIFSMaxBufSize) {
1729 cERROR(1,("rsize %d too large, using MaxBufSize",
1730 volume_info.rsize));
1731 cifs_sb->rsize = CIFSMaxBufSize;
1732 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001734 else /* default */
1735 cifs_sb->rsize = CIFSMaxBufSize;
1736
1737 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1738 cERROR(1,("wsize %d too large using 4096 instead",
1739 volume_info.wsize));
1740 cifs_sb->wsize = 4096;
1741 } else if(volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 cifs_sb->wsize = volume_info.wsize;
1743 else
1744 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1745 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
Steve French6b8edfe2005-08-23 20:26:03 -07001746 cifs_sb->rsize = PAGE_CACHE_SIZE;
1747 /* Windows ME does this */
1748 cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 }
1750 cifs_sb->mnt_uid = volume_info.linux_uid;
1751 cifs_sb->mnt_gid = volume_info.linux_gid;
1752 cifs_sb->mnt_file_mode = volume_info.file_mode;
1753 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1754 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1755
1756 if(volume_info.noperm)
1757 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1758 if(volume_info.setuids)
1759 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1760 if(volume_info.server_ino)
1761 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001762 if(volume_info.remap)
1763 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 if(volume_info.no_xattr)
1765 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001766 if(volume_info.sfu_emul)
1767 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001768 if(volume_info.nobrl)
1769 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001770
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001772 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1774 }
1775
1776 tcon =
1777 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1778 volume_info.username);
1779 if (tcon) {
1780 cFYI(1, ("Found match on UNC path "));
1781 /* we can have only one retry value for a connection
1782 to a share so for resources mounted more than once
1783 to the same server share the last value passed in
1784 for the retry flag is used */
1785 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001786 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 } else {
1788 tcon = tconInfoAlloc();
1789 if (tcon == NULL)
1790 rc = -ENOMEM;
1791 else {
1792 /* check for null share name ie connect to dfs root */
1793
1794 /* BB check if this works for exactly length three strings */
1795 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1796 && (strchr(volume_info.UNC + 3, '/') ==
1797 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001798 rc = connect_to_dfs_path(xid, pSesInfo,
1799 "", cifs_sb->local_nls,
1800 cifs_sb->mnt_cifs_flags &
1801 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001802 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 FreeXid(xid);
1804 return -ENODEV;
1805 } else {
1806 rc = CIFSTCon(xid, pSesInfo,
1807 volume_info.UNC,
1808 tcon, cifs_sb->local_nls);
1809 cFYI(1, ("CIFS Tcon rc = %d", rc));
1810 }
1811 if (!rc) {
1812 atomic_inc(&pSesInfo->inUse);
1813 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001814 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 }
1816 }
1817 }
1818 }
1819 if(pSesInfo) {
1820 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1821 sb->s_maxbytes = (u64) 1 << 63;
1822 } else
1823 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1824 }
1825
1826 sb->s_time_gran = 100;
1827
1828/* on error free sesinfo and tcon struct if needed */
1829 if (rc) {
1830 /* if session setup failed, use count is zero but
1831 we still need to free cifsd thread */
1832 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1833 spin_lock(&GlobalMid_Lock);
1834 srvTcp->tcpStatus = CifsExiting;
1835 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001836 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001838 wait_for_completion(&cifsd_complete);
1839 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 }
1841 /* If find_unc succeeded then rc == 0 so we can not end */
1842 if (tcon) /* up accidently freeing someone elses tcon struct */
1843 tconInfoFree(tcon);
1844 if (existingCifsSes == NULL) {
1845 if (pSesInfo) {
1846 if ((pSesInfo->server) &&
1847 (pSesInfo->status == CifsGood)) {
1848 int temp_rc;
1849 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1850 /* if the socketUseCount is now zero */
1851 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001852 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001854 wait_for_completion(&cifsd_complete);
1855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 } else
1857 cFYI(1, ("No session or bad tcon"));
1858 sesInfoFree(pSesInfo);
1859 /* pSesInfo = NULL; */
1860 }
1861 }
1862 } else {
1863 atomic_inc(&tcon->useCount);
1864 cifs_sb->tcon = tcon;
1865 tcon->ses = pSesInfo;
1866
1867 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001868 CIFSSMBQFSDeviceInfo(xid, tcon);
1869 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001871 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 if(!volume_info.no_psx_acl) {
1873 if(CIFS_UNIX_POSIX_ACL_CAP &
1874 le64_to_cpu(tcon->fsUnixInfo.Capability))
1875 cFYI(1,("server negotiated posix acl support"));
1876 sb->s_flags |= MS_POSIXACL;
1877 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001878
1879 /* Try and negotiate POSIX pathnames if we can. */
1880 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1881 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French45abc6e2005-06-23 13:42:03 -05001882 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
Jeremy Allisonac670552005-06-22 17:26:35 -07001883 cFYI(1,("negotiated posix pathnames support"));
1884 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1885 } else {
1886 cFYI(1,("posix pathnames support requested but not supported"));
1887 }
1888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 }
1890 }
Steve French3e844692005-10-03 13:37:24 -07001891 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
1892 cifs_sb->wsize = min(cifs_sb->wsize,
1893 (tcon->ses->server->maxBuf -
1894 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07001895 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
1896 cifs_sb->rsize = min(cifs_sb->rsize,
1897 (tcon->ses->server->maxBuf -
1898 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
1900
1901 /* volume_info.password is freed above when existing session found
1902 (in which case it is not needed anymore) but when new sesion is created
1903 the password ptr is put in the new session structure (in which case the
1904 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001905 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 FreeXid(xid);
1907 return rc;
1908}
1909
1910static int
1911CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1912 char session_key[CIFS_SESSION_KEY_SIZE],
1913 const struct nls_table *nls_codepage)
1914{
1915 struct smb_hdr *smb_buffer;
1916 struct smb_hdr *smb_buffer_response;
1917 SESSION_SETUP_ANDX *pSMB;
1918 SESSION_SETUP_ANDX *pSMBr;
1919 char *bcc_ptr;
1920 char *user;
1921 char *domain;
1922 int rc = 0;
1923 int remaining_words = 0;
1924 int bytes_returned = 0;
1925 int len;
1926 __u32 capabilities;
1927 __u16 count;
1928
1929 cFYI(1, ("In sesssetup "));
1930 if(ses == NULL)
1931 return -EINVAL;
1932 user = ses->userName;
1933 domain = ses->domainName;
1934 smb_buffer = cifs_buf_get();
1935 if (smb_buffer == NULL) {
1936 return -ENOMEM;
1937 }
1938 smb_buffer_response = smb_buffer;
1939 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1940
1941 /* send SMBsessionSetup here */
1942 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1943 NULL /* no tCon exists yet */ , 13 /* wct */ );
1944
Steve French1982c342005-08-17 12:38:22 -07001945 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 pSMB->req_no_secext.AndXCommand = 0xFF;
1947 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1948 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1949
1950 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1951 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1952
1953 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1954 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1955 if (ses->capabilities & CAP_UNICODE) {
1956 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1957 capabilities |= CAP_UNICODE;
1958 }
1959 if (ses->capabilities & CAP_STATUS32) {
1960 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1961 capabilities |= CAP_STATUS32;
1962 }
1963 if (ses->capabilities & CAP_DFS) {
1964 smb_buffer->Flags2 |= SMBFLG2_DFS;
1965 capabilities |= CAP_DFS;
1966 }
1967 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1968
1969 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1970 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1971
1972 pSMB->req_no_secext.CaseSensitivePasswordLength =
1973 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1974 bcc_ptr = pByteArea(smb_buffer);
1975 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1976 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1977 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1978 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1979
1980 if (ses->capabilities & CAP_UNICODE) {
1981 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1982 *bcc_ptr = 0;
1983 bcc_ptr++;
1984 }
1985 if(user == NULL)
1986 bytes_returned = 0; /* skill null user */
1987 else
1988 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08001989 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 nls_codepage);
1991 /* convert number of 16 bit words to bytes */
1992 bcc_ptr += 2 * bytes_returned;
1993 bcc_ptr += 2; /* trailing null */
1994 if (domain == NULL)
1995 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08001996 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 "CIFS_LINUX_DOM", 32, nls_codepage);
1998 else
1999 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002000 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 nls_codepage);
2002 bcc_ptr += 2 * bytes_returned;
2003 bcc_ptr += 2;
2004 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002005 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 32, nls_codepage);
2007 bcc_ptr += 2 * bytes_returned;
2008 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002009 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 32, nls_codepage);
2011 bcc_ptr += 2 * bytes_returned;
2012 bcc_ptr += 2;
2013 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002014 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 64, nls_codepage);
2016 bcc_ptr += 2 * bytes_returned;
2017 bcc_ptr += 2;
2018 } else {
2019 if(user != NULL) {
2020 strncpy(bcc_ptr, user, 200);
2021 bcc_ptr += strnlen(user, 200);
2022 }
2023 *bcc_ptr = 0;
2024 bcc_ptr++;
2025 if (domain == NULL) {
2026 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2027 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2028 } else {
2029 strncpy(bcc_ptr, domain, 64);
2030 bcc_ptr += strnlen(domain, 64);
2031 *bcc_ptr = 0;
2032 bcc_ptr++;
2033 }
2034 strcpy(bcc_ptr, "Linux version ");
2035 bcc_ptr += strlen("Linux version ");
2036 strcpy(bcc_ptr, system_utsname.release);
2037 bcc_ptr += strlen(system_utsname.release) + 1;
2038 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2039 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2040 }
2041 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2042 smb_buffer->smb_buf_length += count;
2043 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2044
2045 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2046 &bytes_returned, 1);
2047 if (rc) {
2048/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2049 } else if ((smb_buffer_response->WordCount == 3)
2050 || (smb_buffer_response->WordCount == 4)) {
2051 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2052 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2053 if (action & GUEST_LOGIN)
2054 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2055 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2056 cFYI(1, ("UID = %d ", ses->Suid));
2057 /* response can have either 3 or 4 word count - Samba sends 3 */
2058 bcc_ptr = pByteArea(smb_buffer_response);
2059 if ((pSMBr->resp.hdr.WordCount == 3)
2060 || ((pSMBr->resp.hdr.WordCount == 4)
2061 && (blob_len < pSMBr->resp.ByteCount))) {
2062 if (pSMBr->resp.hdr.WordCount == 4)
2063 bcc_ptr += blob_len;
2064
2065 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2066 if ((long) (bcc_ptr) % 2) {
2067 remaining_words =
2068 (BCC(smb_buffer_response) - 1) /2;
2069 bcc_ptr++; /* Unicode strings must be word aligned */
2070 } else {
2071 remaining_words =
2072 BCC(smb_buffer_response) / 2;
2073 }
2074 len =
2075 UniStrnlen((wchar_t *) bcc_ptr,
2076 remaining_words - 1);
2077/* We look for obvious messed up bcc or strings in response so we do not go off
2078 the end since (at least) WIN2K and Windows XP have a major bug in not null
2079 terminating last Unicode string in response */
Pekka Enberge915fc42005-09-06 15:18:35 -07002080 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002081 if(ses->serverOS == NULL)
2082 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002084 (__le16 *)bcc_ptr, len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 bcc_ptr += 2 * (len + 1);
2086 remaining_words -= len + 1;
2087 ses->serverOS[2 * len] = 0;
2088 ses->serverOS[1 + (2 * len)] = 0;
2089 if (remaining_words > 0) {
2090 len = UniStrnlen((wchar_t *)bcc_ptr,
2091 remaining_words-1);
Pekka Enberge915fc42005-09-06 15:18:35 -07002092 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002093 if(ses->serverNOS == NULL)
2094 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002096 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 bcc_ptr += 2 * (len + 1);
2098 ses->serverNOS[2 * len] = 0;
2099 ses->serverNOS[1 + (2 * len)] = 0;
2100 if(strncmp(ses->serverNOS,
2101 "NT LAN Manager 4",16) == 0) {
2102 cFYI(1,("NT4 server"));
2103 ses->flags |= CIFS_SES_NT4;
2104 }
2105 remaining_words -= len + 1;
2106 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002107 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2109 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002110 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002111 if(ses->serverDomain == NULL)
2112 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002114 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 bcc_ptr += 2 * (len + 1);
2116 ses->serverDomain[2*len] = 0;
2117 ses->serverDomain[1+(2*len)] = 0;
2118 } /* else no more room so create dummy domain string */
2119 else
Steve French433dc242005-04-28 22:41:08 -07002120 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002121 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002123 /* if these kcallocs fail not much we
2124 can do, but better to not fail the
2125 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002127 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002129 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 }
2131 } else { /* ASCII */
2132 len = strnlen(bcc_ptr, 1024);
2133 if (((long) bcc_ptr + len) - (long)
2134 pByteArea(smb_buffer_response)
2135 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07002136 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002137 if(ses->serverOS == NULL)
2138 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 strncpy(ses->serverOS,bcc_ptr, len);
2140
2141 bcc_ptr += len;
2142 bcc_ptr[0] = 0; /* null terminate the string */
2143 bcc_ptr++;
2144
2145 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002146 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002147 if(ses->serverNOS == NULL)
2148 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 strncpy(ses->serverNOS, bcc_ptr, len);
2150 bcc_ptr += len;
2151 bcc_ptr[0] = 0;
2152 bcc_ptr++;
2153
2154 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002155 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002156 if(ses->serverDomain == NULL)
2157 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 strncpy(ses->serverDomain, bcc_ptr, len);
2159 bcc_ptr += len;
2160 bcc_ptr[0] = 0;
2161 bcc_ptr++;
2162 } else
2163 cFYI(1,
2164 ("Variable field of length %d extends beyond end of smb ",
2165 len));
2166 }
2167 } else {
2168 cERROR(1,
2169 (" Security Blob Length extends beyond end of SMB"));
2170 }
2171 } else {
2172 cERROR(1,
2173 (" Invalid Word count %d: ",
2174 smb_buffer_response->WordCount));
2175 rc = -EIO;
2176 }
Steve French433dc242005-04-28 22:41:08 -07002177sesssetup_nomem: /* do not return an error on nomem for the info strings,
2178 since that could make reconnection harder, and
2179 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 if (smb_buffer)
2181 cifs_buf_release(smb_buffer);
2182
2183 return rc;
2184}
2185
2186static int
2187CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2188 char *SecurityBlob,int SecurityBlobLength,
2189 const struct nls_table *nls_codepage)
2190{
2191 struct smb_hdr *smb_buffer;
2192 struct smb_hdr *smb_buffer_response;
2193 SESSION_SETUP_ANDX *pSMB;
2194 SESSION_SETUP_ANDX *pSMBr;
2195 char *bcc_ptr;
2196 char *user;
2197 char *domain;
2198 int rc = 0;
2199 int remaining_words = 0;
2200 int bytes_returned = 0;
2201 int len;
2202 __u32 capabilities;
2203 __u16 count;
2204
2205 cFYI(1, ("In spnego sesssetup "));
2206 if(ses == NULL)
2207 return -EINVAL;
2208 user = ses->userName;
2209 domain = ses->domainName;
2210
2211 smb_buffer = cifs_buf_get();
2212 if (smb_buffer == NULL) {
2213 return -ENOMEM;
2214 }
2215 smb_buffer_response = smb_buffer;
2216 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2217
2218 /* send SMBsessionSetup here */
2219 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2220 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002221
2222 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2224 pSMB->req.AndXCommand = 0xFF;
2225 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2226 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2227
2228 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2229 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2230
2231 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2232 CAP_EXTENDED_SECURITY;
2233 if (ses->capabilities & CAP_UNICODE) {
2234 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2235 capabilities |= CAP_UNICODE;
2236 }
2237 if (ses->capabilities & CAP_STATUS32) {
2238 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2239 capabilities |= CAP_STATUS32;
2240 }
2241 if (ses->capabilities & CAP_DFS) {
2242 smb_buffer->Flags2 |= SMBFLG2_DFS;
2243 capabilities |= CAP_DFS;
2244 }
2245 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2246
2247 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2248 bcc_ptr = pByteArea(smb_buffer);
2249 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2250 bcc_ptr += SecurityBlobLength;
2251
2252 if (ses->capabilities & CAP_UNICODE) {
2253 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2254 *bcc_ptr = 0;
2255 bcc_ptr++;
2256 }
2257 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002258 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2260 bcc_ptr += 2; /* trailing null */
2261 if (domain == NULL)
2262 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002263 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 "CIFS_LINUX_DOM", 32, nls_codepage);
2265 else
2266 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002267 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 nls_codepage);
2269 bcc_ptr += 2 * bytes_returned;
2270 bcc_ptr += 2;
2271 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002272 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 32, nls_codepage);
2274 bcc_ptr += 2 * bytes_returned;
2275 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002276 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 nls_codepage);
2278 bcc_ptr += 2 * bytes_returned;
2279 bcc_ptr += 2;
2280 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002281 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 64, nls_codepage);
2283 bcc_ptr += 2 * bytes_returned;
2284 bcc_ptr += 2;
2285 } else {
2286 strncpy(bcc_ptr, user, 200);
2287 bcc_ptr += strnlen(user, 200);
2288 *bcc_ptr = 0;
2289 bcc_ptr++;
2290 if (domain == NULL) {
2291 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2292 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2293 } else {
2294 strncpy(bcc_ptr, domain, 64);
2295 bcc_ptr += strnlen(domain, 64);
2296 *bcc_ptr = 0;
2297 bcc_ptr++;
2298 }
2299 strcpy(bcc_ptr, "Linux version ");
2300 bcc_ptr += strlen("Linux version ");
2301 strcpy(bcc_ptr, system_utsname.release);
2302 bcc_ptr += strlen(system_utsname.release) + 1;
2303 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2304 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2305 }
2306 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2307 smb_buffer->smb_buf_length += count;
2308 pSMB->req.ByteCount = cpu_to_le16(count);
2309
2310 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2311 &bytes_returned, 1);
2312 if (rc) {
2313/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2314 } else if ((smb_buffer_response->WordCount == 3)
2315 || (smb_buffer_response->WordCount == 4)) {
2316 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2317 __u16 blob_len =
2318 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2319 if (action & GUEST_LOGIN)
2320 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2321 if (ses) {
2322 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2323 cFYI(1, ("UID = %d ", ses->Suid));
2324 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2325
2326 /* BB Fix below to make endian neutral !! */
2327
2328 if ((pSMBr->resp.hdr.WordCount == 3)
2329 || ((pSMBr->resp.hdr.WordCount == 4)
2330 && (blob_len <
2331 pSMBr->resp.ByteCount))) {
2332 if (pSMBr->resp.hdr.WordCount == 4) {
2333 bcc_ptr +=
2334 blob_len;
2335 cFYI(1,
2336 ("Security Blob Length %d ",
2337 blob_len));
2338 }
2339
2340 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2341 if ((long) (bcc_ptr) % 2) {
2342 remaining_words =
2343 (BCC(smb_buffer_response)
2344 - 1) / 2;
2345 bcc_ptr++; /* Unicode strings must be word aligned */
2346 } else {
2347 remaining_words =
2348 BCC
2349 (smb_buffer_response) / 2;
2350 }
2351 len =
2352 UniStrnlen((wchar_t *) bcc_ptr,
2353 remaining_words - 1);
2354/* We look for obvious messed up bcc or strings in response so we do not go off
2355 the end since (at least) WIN2K and Windows XP have a major bug in not null
2356 terminating last Unicode string in response */
2357 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002358 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002360 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 bcc_ptr, len,
2362 nls_codepage);
2363 bcc_ptr += 2 * (len + 1);
2364 remaining_words -= len + 1;
2365 ses->serverOS[2 * len] = 0;
2366 ses->serverOS[1 + (2 * len)] = 0;
2367 if (remaining_words > 0) {
2368 len = UniStrnlen((wchar_t *)bcc_ptr,
2369 remaining_words
2370 - 1);
2371 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002372 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 GFP_KERNEL);
2374 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002375 (__le16 *)bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 len,
2377 nls_codepage);
2378 bcc_ptr += 2 * (len + 1);
2379 ses->serverNOS[2 * len] = 0;
2380 ses->serverNOS[1 + (2 * len)] = 0;
2381 remaining_words -= len + 1;
2382 if (remaining_words > 0) {
2383 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2384 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Pekka Enberge915fc42005-09-06 15:18:35 -07002385 ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002387 (__le16 *)bcc_ptr,
2388 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 bcc_ptr += 2*(len+1);
2390 ses->serverDomain[2*len] = 0;
2391 ses->serverDomain[1+(2*len)] = 0;
2392 } /* else no more room so create dummy domain string */
2393 else
2394 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002395 kzalloc(2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 } else { /* no room so create dummy domain and NOS string */
Pekka Enberge915fc42005-09-06 15:18:35 -07002397 ses->serverDomain = kzalloc(2, GFP_KERNEL);
2398 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 }
2400 } else { /* ASCII */
2401
2402 len = strnlen(bcc_ptr, 1024);
2403 if (((long) bcc_ptr + len) - (long)
2404 pByteArea(smb_buffer_response)
2405 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07002406 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 strncpy(ses->serverOS, bcc_ptr, len);
2408
2409 bcc_ptr += len;
2410 bcc_ptr[0] = 0; /* null terminate the string */
2411 bcc_ptr++;
2412
2413 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002414 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 strncpy(ses->serverNOS, bcc_ptr, len);
2416 bcc_ptr += len;
2417 bcc_ptr[0] = 0;
2418 bcc_ptr++;
2419
2420 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002421 ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 strncpy(ses->serverDomain, bcc_ptr, len);
2423 bcc_ptr += len;
2424 bcc_ptr[0] = 0;
2425 bcc_ptr++;
2426 } else
2427 cFYI(1,
2428 ("Variable field of length %d extends beyond end of smb ",
2429 len));
2430 }
2431 } else {
2432 cERROR(1,
2433 (" Security Blob Length extends beyond end of SMB"));
2434 }
2435 } else {
2436 cERROR(1, ("No session structure passed in."));
2437 }
2438 } else {
2439 cERROR(1,
2440 (" Invalid Word count %d: ",
2441 smb_buffer_response->WordCount));
2442 rc = -EIO;
2443 }
2444
2445 if (smb_buffer)
2446 cifs_buf_release(smb_buffer);
2447
2448 return rc;
2449}
2450
2451static int
2452CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2453 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2454 const struct nls_table *nls_codepage)
2455{
2456 struct smb_hdr *smb_buffer;
2457 struct smb_hdr *smb_buffer_response;
2458 SESSION_SETUP_ANDX *pSMB;
2459 SESSION_SETUP_ANDX *pSMBr;
2460 char *bcc_ptr;
2461 char *domain;
2462 int rc = 0;
2463 int remaining_words = 0;
2464 int bytes_returned = 0;
2465 int len;
2466 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2467 PNEGOTIATE_MESSAGE SecurityBlob;
2468 PCHALLENGE_MESSAGE SecurityBlob2;
2469 __u32 negotiate_flags, capabilities;
2470 __u16 count;
2471
2472 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2473 if(ses == NULL)
2474 return -EINVAL;
2475 domain = ses->domainName;
2476 *pNTLMv2_flag = FALSE;
2477 smb_buffer = cifs_buf_get();
2478 if (smb_buffer == NULL) {
2479 return -ENOMEM;
2480 }
2481 smb_buffer_response = smb_buffer;
2482 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2483 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2484
2485 /* send SMBsessionSetup here */
2486 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2487 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002488
2489 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2491 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2492
2493 pSMB->req.AndXCommand = 0xFF;
2494 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2495 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2496
2497 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2498 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2499
2500 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2501 CAP_EXTENDED_SECURITY;
2502 if (ses->capabilities & CAP_UNICODE) {
2503 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2504 capabilities |= CAP_UNICODE;
2505 }
2506 if (ses->capabilities & CAP_STATUS32) {
2507 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2508 capabilities |= CAP_STATUS32;
2509 }
2510 if (ses->capabilities & CAP_DFS) {
2511 smb_buffer->Flags2 |= SMBFLG2_DFS;
2512 capabilities |= CAP_DFS;
2513 }
2514 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2515
2516 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2517 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2518 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2519 SecurityBlob->MessageType = NtLmNegotiate;
2520 negotiate_flags =
2521 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2522 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2523 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2524 if(sign_CIFS_PDUs)
2525 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2526 if(ntlmv2_support)
2527 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2528 /* setup pointers to domain name and workstation name */
2529 bcc_ptr += SecurityBlobLength;
2530
2531 SecurityBlob->WorkstationName.Buffer = 0;
2532 SecurityBlob->WorkstationName.Length = 0;
2533 SecurityBlob->WorkstationName.MaximumLength = 0;
2534
2535 if (domain == NULL) {
2536 SecurityBlob->DomainName.Buffer = 0;
2537 SecurityBlob->DomainName.Length = 0;
2538 SecurityBlob->DomainName.MaximumLength = 0;
2539 } else {
2540 __u16 len;
2541 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2542 strncpy(bcc_ptr, domain, 63);
2543 len = strnlen(domain, 64);
2544 SecurityBlob->DomainName.MaximumLength =
2545 cpu_to_le16(len);
2546 SecurityBlob->DomainName.Buffer =
2547 cpu_to_le32((long) &SecurityBlob->
2548 DomainString -
2549 (long) &SecurityBlob->Signature);
2550 bcc_ptr += len;
2551 SecurityBlobLength += len;
2552 SecurityBlob->DomainName.Length =
2553 cpu_to_le16(len);
2554 }
2555 if (ses->capabilities & CAP_UNICODE) {
2556 if ((long) bcc_ptr % 2) {
2557 *bcc_ptr = 0;
2558 bcc_ptr++;
2559 }
2560
2561 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002562 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 32, nls_codepage);
2564 bcc_ptr += 2 * bytes_returned;
2565 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002566 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 nls_codepage);
2568 bcc_ptr += 2 * bytes_returned;
2569 bcc_ptr += 2; /* null terminate Linux version */
2570 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002571 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 64, nls_codepage);
2573 bcc_ptr += 2 * bytes_returned;
2574 *(bcc_ptr + 1) = 0;
2575 *(bcc_ptr + 2) = 0;
2576 bcc_ptr += 2; /* null terminate network opsys string */
2577 *(bcc_ptr + 1) = 0;
2578 *(bcc_ptr + 2) = 0;
2579 bcc_ptr += 2; /* null domain */
2580 } else { /* ASCII */
2581 strcpy(bcc_ptr, "Linux version ");
2582 bcc_ptr += strlen("Linux version ");
2583 strcpy(bcc_ptr, system_utsname.release);
2584 bcc_ptr += strlen(system_utsname.release) + 1;
2585 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2586 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2587 bcc_ptr++; /* empty domain field */
2588 *bcc_ptr = 0;
2589 }
2590 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2591 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2592 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2593 smb_buffer->smb_buf_length += count;
2594 pSMB->req.ByteCount = cpu_to_le16(count);
2595
2596 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2597 &bytes_returned, 1);
2598
2599 if (smb_buffer_response->Status.CifsError ==
2600 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2601 rc = 0;
2602
2603 if (rc) {
2604/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2605 } else if ((smb_buffer_response->WordCount == 3)
2606 || (smb_buffer_response->WordCount == 4)) {
2607 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2608 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2609
2610 if (action & GUEST_LOGIN)
2611 cFYI(1, (" Guest login"));
2612 /* Do we want to set anything in SesInfo struct when guest login? */
2613
2614 bcc_ptr = pByteArea(smb_buffer_response);
2615 /* response can have either 3 or 4 word count - Samba sends 3 */
2616
2617 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2618 if (SecurityBlob2->MessageType != NtLmChallenge) {
2619 cFYI(1,
2620 ("Unexpected NTLMSSP message type received %d",
2621 SecurityBlob2->MessageType));
2622 } else if (ses) {
2623 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2624 cFYI(1, ("UID = %d ", ses->Suid));
2625 if ((pSMBr->resp.hdr.WordCount == 3)
2626 || ((pSMBr->resp.hdr.WordCount == 4)
2627 && (blob_len <
2628 pSMBr->resp.ByteCount))) {
2629
2630 if (pSMBr->resp.hdr.WordCount == 4) {
2631 bcc_ptr += blob_len;
2632 cFYI(1,
2633 ("Security Blob Length %d ",
2634 blob_len));
2635 }
2636
2637 cFYI(1, ("NTLMSSP Challenge rcvd "));
2638
2639 memcpy(ses->server->cryptKey,
2640 SecurityBlob2->Challenge,
2641 CIFS_CRYPTO_KEY_SIZE);
2642 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2643 *pNTLMv2_flag = TRUE;
2644
2645 if((SecurityBlob2->NegotiateFlags &
2646 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2647 || (sign_CIFS_PDUs > 1))
2648 ses->server->secMode |=
2649 SECMODE_SIGN_REQUIRED;
2650 if ((SecurityBlob2->NegotiateFlags &
2651 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2652 ses->server->secMode |=
2653 SECMODE_SIGN_ENABLED;
2654
2655 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2656 if ((long) (bcc_ptr) % 2) {
2657 remaining_words =
2658 (BCC(smb_buffer_response)
2659 - 1) / 2;
2660 bcc_ptr++; /* Unicode strings must be word aligned */
2661 } else {
2662 remaining_words =
2663 BCC
2664 (smb_buffer_response) / 2;
2665 }
2666 len =
2667 UniStrnlen((wchar_t *) bcc_ptr,
2668 remaining_words - 1);
2669/* We look for obvious messed up bcc or strings in response so we do not go off
2670 the end since (at least) WIN2K and Windows XP have a major bug in not null
2671 terminating last Unicode string in response */
2672 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002673 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002675 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 bcc_ptr, len,
2677 nls_codepage);
2678 bcc_ptr += 2 * (len + 1);
2679 remaining_words -= len + 1;
2680 ses->serverOS[2 * len] = 0;
2681 ses->serverOS[1 + (2 * len)] = 0;
2682 if (remaining_words > 0) {
2683 len = UniStrnlen((wchar_t *)
2684 bcc_ptr,
2685 remaining_words
2686 - 1);
2687 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002688 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 GFP_KERNEL);
2690 cifs_strfromUCS_le(ses->
2691 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002692 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 bcc_ptr,
2694 len,
2695 nls_codepage);
2696 bcc_ptr += 2 * (len + 1);
2697 ses->serverNOS[2 * len] = 0;
2698 ses->serverNOS[1 +
2699 (2 * len)] = 0;
2700 remaining_words -= len + 1;
2701 if (remaining_words > 0) {
2702 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2703 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2704 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002705 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 (len +
2707 1),
2708 GFP_KERNEL);
2709 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002710 (ses->serverDomain,
2711 (__le16 *)bcc_ptr,
2712 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 bcc_ptr +=
2714 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002715 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002717 ses->serverDomain
2718 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 = 0;
2720 } /* else no more room so create dummy domain string */
2721 else
2722 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002723 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 GFP_KERNEL);
2725 } else { /* no room so create dummy domain and NOS string */
2726 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002727 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002729 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 }
2731 } else { /* ASCII */
2732 len = strnlen(bcc_ptr, 1024);
2733 if (((long) bcc_ptr + len) - (long)
2734 pByteArea(smb_buffer_response)
2735 <= BCC(smb_buffer_response)) {
2736 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002737 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 GFP_KERNEL);
2739 strncpy(ses->serverOS,
2740 bcc_ptr, len);
2741
2742 bcc_ptr += len;
2743 bcc_ptr[0] = 0; /* null terminate string */
2744 bcc_ptr++;
2745
2746 len = strnlen(bcc_ptr, 1024);
2747 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002748 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 GFP_KERNEL);
2750 strncpy(ses->serverNOS, bcc_ptr, len);
2751 bcc_ptr += len;
2752 bcc_ptr[0] = 0;
2753 bcc_ptr++;
2754
2755 len = strnlen(bcc_ptr, 1024);
2756 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002757 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 GFP_KERNEL);
2759 strncpy(ses->serverDomain, bcc_ptr, len);
2760 bcc_ptr += len;
2761 bcc_ptr[0] = 0;
2762 bcc_ptr++;
2763 } else
2764 cFYI(1,
2765 ("Variable field of length %d extends beyond end of smb ",
2766 len));
2767 }
2768 } else {
2769 cERROR(1,
2770 (" Security Blob Length extends beyond end of SMB"));
2771 }
2772 } else {
2773 cERROR(1, ("No session structure passed in."));
2774 }
2775 } else {
2776 cERROR(1,
2777 (" Invalid Word count %d: ",
2778 smb_buffer_response->WordCount));
2779 rc = -EIO;
2780 }
2781
2782 if (smb_buffer)
2783 cifs_buf_release(smb_buffer);
2784
2785 return rc;
2786}
2787static int
2788CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2789 char *ntlm_session_key, int ntlmv2_flag,
2790 const struct nls_table *nls_codepage)
2791{
2792 struct smb_hdr *smb_buffer;
2793 struct smb_hdr *smb_buffer_response;
2794 SESSION_SETUP_ANDX *pSMB;
2795 SESSION_SETUP_ANDX *pSMBr;
2796 char *bcc_ptr;
2797 char *user;
2798 char *domain;
2799 int rc = 0;
2800 int remaining_words = 0;
2801 int bytes_returned = 0;
2802 int len;
2803 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2804 PAUTHENTICATE_MESSAGE SecurityBlob;
2805 __u32 negotiate_flags, capabilities;
2806 __u16 count;
2807
2808 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2809 if(ses == NULL)
2810 return -EINVAL;
2811 user = ses->userName;
2812 domain = ses->domainName;
2813 smb_buffer = cifs_buf_get();
2814 if (smb_buffer == NULL) {
2815 return -ENOMEM;
2816 }
2817 smb_buffer_response = smb_buffer;
2818 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2819 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2820
2821 /* send SMBsessionSetup here */
2822 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2823 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002824
2825 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2827 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2828 pSMB->req.AndXCommand = 0xFF;
2829 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2830 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2831
2832 pSMB->req.hdr.Uid = ses->Suid;
2833
2834 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2835 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2836
2837 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2838 CAP_EXTENDED_SECURITY;
2839 if (ses->capabilities & CAP_UNICODE) {
2840 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2841 capabilities |= CAP_UNICODE;
2842 }
2843 if (ses->capabilities & CAP_STATUS32) {
2844 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2845 capabilities |= CAP_STATUS32;
2846 }
2847 if (ses->capabilities & CAP_DFS) {
2848 smb_buffer->Flags2 |= SMBFLG2_DFS;
2849 capabilities |= CAP_DFS;
2850 }
2851 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2852
2853 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2854 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2855 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2856 SecurityBlob->MessageType = NtLmAuthenticate;
2857 bcc_ptr += SecurityBlobLength;
2858 negotiate_flags =
2859 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2860 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2861 0x80000000 | NTLMSSP_NEGOTIATE_128;
2862 if(sign_CIFS_PDUs)
2863 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2864 if(ntlmv2_flag)
2865 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2866
2867/* setup pointers to domain name and workstation name */
2868
2869 SecurityBlob->WorkstationName.Buffer = 0;
2870 SecurityBlob->WorkstationName.Length = 0;
2871 SecurityBlob->WorkstationName.MaximumLength = 0;
2872 SecurityBlob->SessionKey.Length = 0;
2873 SecurityBlob->SessionKey.MaximumLength = 0;
2874 SecurityBlob->SessionKey.Buffer = 0;
2875
2876 SecurityBlob->LmChallengeResponse.Length = 0;
2877 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2878 SecurityBlob->LmChallengeResponse.Buffer = 0;
2879
2880 SecurityBlob->NtChallengeResponse.Length =
2881 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2882 SecurityBlob->NtChallengeResponse.MaximumLength =
2883 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2884 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2885 SecurityBlob->NtChallengeResponse.Buffer =
2886 cpu_to_le32(SecurityBlobLength);
2887 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2888 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2889
2890 if (ses->capabilities & CAP_UNICODE) {
2891 if (domain == NULL) {
2892 SecurityBlob->DomainName.Buffer = 0;
2893 SecurityBlob->DomainName.Length = 0;
2894 SecurityBlob->DomainName.MaximumLength = 0;
2895 } else {
2896 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002897 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 nls_codepage);
2899 len *= 2;
2900 SecurityBlob->DomainName.MaximumLength =
2901 cpu_to_le16(len);
2902 SecurityBlob->DomainName.Buffer =
2903 cpu_to_le32(SecurityBlobLength);
2904 bcc_ptr += len;
2905 SecurityBlobLength += len;
2906 SecurityBlob->DomainName.Length =
2907 cpu_to_le16(len);
2908 }
2909 if (user == NULL) {
2910 SecurityBlob->UserName.Buffer = 0;
2911 SecurityBlob->UserName.Length = 0;
2912 SecurityBlob->UserName.MaximumLength = 0;
2913 } else {
2914 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002915 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 nls_codepage);
2917 len *= 2;
2918 SecurityBlob->UserName.MaximumLength =
2919 cpu_to_le16(len);
2920 SecurityBlob->UserName.Buffer =
2921 cpu_to_le32(SecurityBlobLength);
2922 bcc_ptr += len;
2923 SecurityBlobLength += len;
2924 SecurityBlob->UserName.Length =
2925 cpu_to_le16(len);
2926 }
2927
Steve Frenche89dc922005-11-11 15:18:19 -08002928 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 SecurityBlob->WorkstationName.Length *= 2;
2930 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2931 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2932 bcc_ptr += SecurityBlob->WorkstationName.Length;
2933 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2934 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2935
2936 if ((long) bcc_ptr % 2) {
2937 *bcc_ptr = 0;
2938 bcc_ptr++;
2939 }
2940 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002941 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 32, nls_codepage);
2943 bcc_ptr += 2 * bytes_returned;
2944 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002945 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 nls_codepage);
2947 bcc_ptr += 2 * bytes_returned;
2948 bcc_ptr += 2; /* null term version string */
2949 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002950 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 64, nls_codepage);
2952 bcc_ptr += 2 * bytes_returned;
2953 *(bcc_ptr + 1) = 0;
2954 *(bcc_ptr + 2) = 0;
2955 bcc_ptr += 2; /* null terminate network opsys string */
2956 *(bcc_ptr + 1) = 0;
2957 *(bcc_ptr + 2) = 0;
2958 bcc_ptr += 2; /* null domain */
2959 } else { /* ASCII */
2960 if (domain == NULL) {
2961 SecurityBlob->DomainName.Buffer = 0;
2962 SecurityBlob->DomainName.Length = 0;
2963 SecurityBlob->DomainName.MaximumLength = 0;
2964 } else {
2965 __u16 len;
2966 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2967 strncpy(bcc_ptr, domain, 63);
2968 len = strnlen(domain, 64);
2969 SecurityBlob->DomainName.MaximumLength =
2970 cpu_to_le16(len);
2971 SecurityBlob->DomainName.Buffer =
2972 cpu_to_le32(SecurityBlobLength);
2973 bcc_ptr += len;
2974 SecurityBlobLength += len;
2975 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2976 }
2977 if (user == NULL) {
2978 SecurityBlob->UserName.Buffer = 0;
2979 SecurityBlob->UserName.Length = 0;
2980 SecurityBlob->UserName.MaximumLength = 0;
2981 } else {
2982 __u16 len;
2983 strncpy(bcc_ptr, user, 63);
2984 len = strnlen(user, 64);
2985 SecurityBlob->UserName.MaximumLength =
2986 cpu_to_le16(len);
2987 SecurityBlob->UserName.Buffer =
2988 cpu_to_le32(SecurityBlobLength);
2989 bcc_ptr += len;
2990 SecurityBlobLength += len;
2991 SecurityBlob->UserName.Length = cpu_to_le16(len);
2992 }
2993 /* BB fill in our workstation name if known BB */
2994
2995 strcpy(bcc_ptr, "Linux version ");
2996 bcc_ptr += strlen("Linux version ");
2997 strcpy(bcc_ptr, system_utsname.release);
2998 bcc_ptr += strlen(system_utsname.release) + 1;
2999 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3000 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3001 bcc_ptr++; /* null domain */
3002 *bcc_ptr = 0;
3003 }
3004 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3005 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3006 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3007 smb_buffer->smb_buf_length += count;
3008 pSMB->req.ByteCount = cpu_to_le16(count);
3009
3010 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3011 &bytes_returned, 1);
3012 if (rc) {
3013/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3014 } else if ((smb_buffer_response->WordCount == 3)
3015 || (smb_buffer_response->WordCount == 4)) {
3016 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3017 __u16 blob_len =
3018 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3019 if (action & GUEST_LOGIN)
3020 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3021/* if(SecurityBlob2->MessageType != NtLm??){
3022 cFYI("Unexpected message type on auth response is %d "));
3023 } */
3024 if (ses) {
3025 cFYI(1,
3026 ("Does UID on challenge %d match auth response UID %d ",
3027 ses->Suid, smb_buffer_response->Uid));
3028 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3029 bcc_ptr = pByteArea(smb_buffer_response);
3030 /* response can have either 3 or 4 word count - Samba sends 3 */
3031 if ((pSMBr->resp.hdr.WordCount == 3)
3032 || ((pSMBr->resp.hdr.WordCount == 4)
3033 && (blob_len <
3034 pSMBr->resp.ByteCount))) {
3035 if (pSMBr->resp.hdr.WordCount == 4) {
3036 bcc_ptr +=
3037 blob_len;
3038 cFYI(1,
3039 ("Security Blob Length %d ",
3040 blob_len));
3041 }
3042
3043 cFYI(1,
3044 ("NTLMSSP response to Authenticate "));
3045
3046 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3047 if ((long) (bcc_ptr) % 2) {
3048 remaining_words =
3049 (BCC(smb_buffer_response)
3050 - 1) / 2;
3051 bcc_ptr++; /* Unicode strings must be word aligned */
3052 } else {
3053 remaining_words = BCC(smb_buffer_response) / 2;
3054 }
3055 len =
3056 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3057/* We look for obvious messed up bcc or strings in response so we do not go off
3058 the end since (at least) WIN2K and Windows XP have a major bug in not null
3059 terminating last Unicode string in response */
3060 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003061 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003063 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 bcc_ptr, len,
3065 nls_codepage);
3066 bcc_ptr += 2 * (len + 1);
3067 remaining_words -= len + 1;
3068 ses->serverOS[2 * len] = 0;
3069 ses->serverOS[1 + (2 * len)] = 0;
3070 if (remaining_words > 0) {
3071 len = UniStrnlen((wchar_t *)
3072 bcc_ptr,
3073 remaining_words
3074 - 1);
3075 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003076 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 GFP_KERNEL);
3078 cifs_strfromUCS_le(ses->
3079 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003080 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 bcc_ptr,
3082 len,
3083 nls_codepage);
3084 bcc_ptr += 2 * (len + 1);
3085 ses->serverNOS[2 * len] = 0;
3086 ses->serverNOS[1+(2*len)] = 0;
3087 remaining_words -= len + 1;
3088 if (remaining_words > 0) {
3089 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3090 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3091 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003092 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 (len +
3094 1),
3095 GFP_KERNEL);
3096 cifs_strfromUCS_le
3097 (ses->
3098 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003099 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 bcc_ptr, len,
3101 nls_codepage);
3102 bcc_ptr +=
3103 2 * (len + 1);
3104 ses->
3105 serverDomain[2
3106 * len]
3107 = 0;
3108 ses->
3109 serverDomain[1
3110 +
3111 (2
3112 *
3113 len)]
3114 = 0;
3115 } /* else no more room so create dummy domain string */
3116 else
Pekka Enberge915fc42005-09-06 15:18:35 -07003117 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 } else { /* no room so create dummy domain and NOS string */
Pekka Enberge915fc42005-09-06 15:18:35 -07003119 ses->serverDomain = kzalloc(2, GFP_KERNEL);
3120 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 }
3122 } else { /* ASCII */
3123 len = strnlen(bcc_ptr, 1024);
3124 if (((long) bcc_ptr + len) -
3125 (long) pByteArea(smb_buffer_response)
3126 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07003127 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 strncpy(ses->serverOS,bcc_ptr, len);
3129
3130 bcc_ptr += len;
3131 bcc_ptr[0] = 0; /* null terminate the string */
3132 bcc_ptr++;
3133
3134 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07003135 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 strncpy(ses->serverNOS, bcc_ptr, len);
3137 bcc_ptr += len;
3138 bcc_ptr[0] = 0;
3139 bcc_ptr++;
3140
3141 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07003142 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 strncpy(ses->serverDomain, bcc_ptr, len);
3144 bcc_ptr += len;
3145 bcc_ptr[0] = 0;
3146 bcc_ptr++;
3147 } else
3148 cFYI(1,
3149 ("Variable field of length %d extends beyond end of smb ",
3150 len));
3151 }
3152 } else {
3153 cERROR(1,
3154 (" Security Blob Length extends beyond end of SMB"));
3155 }
3156 } else {
3157 cERROR(1, ("No session structure passed in."));
3158 }
3159 } else {
3160 cERROR(1,
3161 (" Invalid Word count %d: ",
3162 smb_buffer_response->WordCount));
3163 rc = -EIO;
3164 }
3165
3166 if (smb_buffer)
3167 cifs_buf_release(smb_buffer);
3168
3169 return rc;
3170}
3171
3172int
3173CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3174 const char *tree, struct cifsTconInfo *tcon,
3175 const struct nls_table *nls_codepage)
3176{
3177 struct smb_hdr *smb_buffer;
3178 struct smb_hdr *smb_buffer_response;
3179 TCONX_REQ *pSMB;
3180 TCONX_RSP *pSMBr;
3181 unsigned char *bcc_ptr;
3182 int rc = 0;
3183 int length;
3184 __u16 count;
3185
3186 if (ses == NULL)
3187 return -EIO;
3188
3189 smb_buffer = cifs_buf_get();
3190 if (smb_buffer == NULL) {
3191 return -ENOMEM;
3192 }
3193 smb_buffer_response = smb_buffer;
3194
3195 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3196 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003197
3198 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 smb_buffer->Uid = ses->Suid;
3200 pSMB = (TCONX_REQ *) smb_buffer;
3201 pSMBr = (TCONX_RSP *) smb_buffer_response;
3202
3203 pSMB->AndXCommand = 0xFF;
3204 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3205 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3206 bcc_ptr = &pSMB->Password[0];
3207 bcc_ptr++; /* skip password */
3208
3209 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3210 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3211
3212 if (ses->capabilities & CAP_STATUS32) {
3213 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3214 }
3215 if (ses->capabilities & CAP_DFS) {
3216 smb_buffer->Flags2 |= SMBFLG2_DFS;
3217 }
3218 if (ses->capabilities & CAP_UNICODE) {
3219 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3220 length =
Steve Frenche89dc922005-11-11 15:18:19 -08003221 cifs_strtoUCS((__le16 *) bcc_ptr, tree, 100, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3223 bcc_ptr += 2; /* skip trailing null */
3224 } else { /* ASCII */
3225
3226 strcpy(bcc_ptr, tree);
3227 bcc_ptr += strlen(tree) + 1;
3228 }
3229 strcpy(bcc_ptr, "?????");
3230 bcc_ptr += strlen("?????");
3231 bcc_ptr += 1;
3232 count = bcc_ptr - &pSMB->Password[0];
3233 pSMB->hdr.smb_buf_length += count;
3234 pSMB->ByteCount = cpu_to_le16(count);
3235
3236 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3237
3238 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3239 /* above now done in SendReceive */
3240 if ((rc == 0) && (tcon != NULL)) {
3241 tcon->tidStatus = CifsGood;
3242 tcon->tid = smb_buffer_response->Tid;
3243 bcc_ptr = pByteArea(smb_buffer_response);
3244 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3245 /* skip service field (NB: this field is always ASCII) */
3246 bcc_ptr += length + 1;
3247 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3248 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3249 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3250 if ((bcc_ptr + (2 * length)) -
3251 pByteArea(smb_buffer_response) <=
3252 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003253 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003255 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003257 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 length, nls_codepage);
3259 bcc_ptr += 2 * length;
3260 bcc_ptr[0] = 0; /* null terminate the string */
3261 bcc_ptr[1] = 0;
3262 bcc_ptr += 2;
3263 }
3264 /* else do not bother copying these informational fields */
3265 } else {
3266 length = strnlen(bcc_ptr, 1024);
3267 if ((bcc_ptr + length) -
3268 pByteArea(smb_buffer_response) <=
3269 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003270 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003272 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 strncpy(tcon->nativeFileSystem, bcc_ptr,
3274 length);
3275 }
3276 /* else do not bother copying these informational fields */
3277 }
3278 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3279 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3280 } else if ((rc == 0) && tcon == NULL) {
3281 /* all we need to save for IPC$ connection */
3282 ses->ipc_tid = smb_buffer_response->Tid;
3283 }
3284
3285 if (smb_buffer)
3286 cifs_buf_release(smb_buffer);
3287 return rc;
3288}
3289
3290int
3291cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3292{
3293 int rc = 0;
3294 int xid;
3295 struct cifsSesInfo *ses = NULL;
3296 struct task_struct *cifsd_task;
3297
3298 xid = GetXid();
3299
3300 if (cifs_sb->tcon) {
3301 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3302 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3303 if (rc == -EBUSY) {
3304 FreeXid(xid);
3305 return 0;
3306 }
3307 tconInfoFree(cifs_sb->tcon);
3308 if ((ses) && (ses->server)) {
3309 /* save off task so we do not refer to ses later */
3310 cifsd_task = ses->server->tsk;
3311 cFYI(1, ("About to do SMBLogoff "));
3312 rc = CIFSSMBLogoff(xid, ses);
3313 if (rc == -EBUSY) {
3314 FreeXid(xid);
3315 return 0;
3316 } else if (rc == -ESHUTDOWN) {
3317 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003318 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003320 wait_for_completion(&cifsd_complete);
3321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 rc = 0;
3323 } /* else - we have an smb session
3324 left on this socket do not kill cifsd */
3325 } else
3326 cFYI(1, ("No session or bad tcon"));
3327 }
3328
3329 cifs_sb->tcon = NULL;
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003330 if (ses)
3331 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 if (ses)
3333 sesInfoFree(ses);
3334
3335 FreeXid(xid);
3336 return rc; /* BB check if we should always return zero here */
3337}
3338
3339int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3340 struct nls_table * nls_info)
3341{
3342 int rc = 0;
3343 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3344 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003345 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
3347 /* what if server changes its buffer size after dropping the session? */
3348 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3349 rc = CIFSSMBNegotiate(xid, pSesInfo);
3350 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3351 rc = CIFSSMBNegotiate(xid, pSesInfo);
3352 if(rc == -EAGAIN)
3353 rc = -EHOSTDOWN;
3354 }
3355 if(rc == 0) {
3356 spin_lock(&GlobalMid_Lock);
3357 if(pSesInfo->server->tcpStatus != CifsExiting)
3358 pSesInfo->server->tcpStatus = CifsGood;
3359 else
3360 rc = -EHOSTDOWN;
3361 spin_unlock(&GlobalMid_Lock);
3362
3363 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003364 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 }
3366 if (!rc) {
3367 pSesInfo->capabilities = pSesInfo->server->capabilities;
3368 if(linuxExtEnabled == 0)
3369 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003370 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3372 pSesInfo->server->secMode,
3373 pSesInfo->server->capabilities,
3374 pSesInfo->server->timeZone));
3375 if (extended_security
3376 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3377 && (pSesInfo->server->secType == NTLMSSP)) {
3378 cFYI(1, ("New style sesssetup "));
3379 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3380 NULL /* security blob */,
3381 0 /* blob length */,
3382 nls_info);
3383 } else if (extended_security
3384 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3385 && (pSesInfo->server->secType == RawNTLMSSP)) {
3386 cFYI(1, ("NTLMSSP sesssetup "));
3387 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3388 pSesInfo,
3389 &ntlmv2_flag,
3390 nls_info);
3391 if (!rc) {
3392 if(ntlmv2_flag) {
3393 char * v2_response;
3394 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3395 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3396 nls_info)) {
3397 rc = -ENOMEM;
3398 goto ss_err_exit;
3399 } else
3400 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3401 if(v2_response) {
3402 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003403 /* if(first_time)
3404 cifs_calculate_ntlmv2_mac_key(
3405 pSesInfo->server->mac_signing_key,
3406 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 kfree(v2_response);
3408 /* BB Put dummy sig in SessSetup PDU? */
3409 } else {
3410 rc = -ENOMEM;
3411 goto ss_err_exit;
3412 }
3413
3414 } else {
3415 SMBNTencrypt(pSesInfo->password,
3416 pSesInfo->server->cryptKey,
3417 ntlm_session_key);
3418
Steve Frenchad009ac2005-04-28 22:41:05 -07003419 if(first_time)
3420 cifs_calculate_mac_key(
3421 pSesInfo->server->mac_signing_key,
3422 ntlm_session_key,
3423 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 }
3425 /* for better security the weaker lanman hash not sent
3426 in AuthSessSetup so we no longer calculate it */
3427
3428 rc = CIFSNTLMSSPAuthSessSetup(xid,
3429 pSesInfo,
3430 ntlm_session_key,
3431 ntlmv2_flag,
3432 nls_info);
3433 }
3434 } else { /* old style NTLM 0.12 session setup */
3435 SMBNTencrypt(pSesInfo->password,
3436 pSesInfo->server->cryptKey,
3437 ntlm_session_key);
3438
Steve Frenchad009ac2005-04-28 22:41:05 -07003439 if(first_time)
3440 cifs_calculate_mac_key(
3441 pSesInfo->server->mac_signing_key,
3442 ntlm_session_key, pSesInfo->password);
3443
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 rc = CIFSSessSetup(xid, pSesInfo,
3445 ntlm_session_key, nls_info);
3446 }
3447 if (rc) {
3448 cERROR(1,("Send error in SessSetup = %d",rc));
3449 } else {
3450 cFYI(1,("CIFS Session Established successfully"));
3451 pSesInfo->status = CifsGood;
3452 }
3453 }
3454ss_err_exit:
3455 return rc;
3456}
3457