blob: 651f3b6cebed3d59f73c4c360319e7c514e50e57 [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 Frenchbf820672005-12-01 22:32:42 -080085 unsigned krb5:1;
86 unsigned ntlm:1;
87 unsigned ntlmv2:1;
88 unsigned nullauth:1; /* attempt to authenticate with null user */
89 unsigned sign:1;
90 unsigned seal:1; /* encrypt */
Steve Frenchc46fa8a2005-08-18 20:49:57 -070091 unsigned nocase; /* request case insensitive filenames */
92 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 unsigned int rsize;
94 unsigned int wsize;
95 unsigned int sockopt;
96 unsigned short int port;
97};
98
99static int ipv4_connect(struct sockaddr_in *psin_server,
100 struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700101 char * netb_name,
102 char * server_netb_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static int ipv6_connect(struct sockaddr_in6 *psin_server,
104 struct socket **csocket);
105
106
107 /*
108 * cifs tcp session reconnection
109 *
110 * mark tcp session as reconnecting so temporarily locked
111 * mark all smb sessions as reconnecting for tcp session
112 * reconnect tcp session
113 * wake up waiters on reconnection? - (not needed currently)
114 */
115
116int
117cifs_reconnect(struct TCP_Server_Info *server)
118{
119 int rc = 0;
120 struct list_head *tmp;
121 struct cifsSesInfo *ses;
122 struct cifsTconInfo *tcon;
123 struct mid_q_entry * mid_entry;
124
125 spin_lock(&GlobalMid_Lock);
126 if(server->tcpStatus == CifsExiting) {
127 /* the demux thread will exit normally
128 next time through the loop */
129 spin_unlock(&GlobalMid_Lock);
130 return rc;
131 } else
132 server->tcpStatus = CifsNeedReconnect;
133 spin_unlock(&GlobalMid_Lock);
134 server->maxBuf = 0;
135
Steve Frenche4eb2952005-04-28 22:41:09 -0700136 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138 /* before reconnecting the tcp session, mark the smb session (uid)
139 and the tid bad so they are not used until reconnected */
140 read_lock(&GlobalSMBSeslock);
141 list_for_each(tmp, &GlobalSMBSessionList) {
142 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
143 if (ses->server) {
144 if (ses->server == server) {
145 ses->status = CifsNeedReconnect;
146 ses->ipc_tid = 0;
147 }
148 }
149 /* else tcp and smb sessions need reconnection */
150 }
151 list_for_each(tmp, &GlobalTreeConnectionList) {
152 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
153 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
154 tcon->tidStatus = CifsNeedReconnect;
155 }
156 }
157 read_unlock(&GlobalSMBSeslock);
158 /* do not want to be sending data on a socket we are freeing */
159 down(&server->tcpSem);
160 if(server->ssocket) {
161 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
162 server->ssocket->flags));
163 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
164 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
165 server->ssocket->flags));
166 sock_release(server->ssocket);
167 server->ssocket = NULL;
168 }
169
170 spin_lock(&GlobalMid_Lock);
171 list_for_each(tmp, &server->pending_mid_q) {
172 mid_entry = list_entry(tmp, struct
173 mid_q_entry,
174 qhead);
175 if(mid_entry) {
176 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700177 /* Mark other intransit requests as needing
178 retry so we do not immediately mark the
179 session bad again (ie after we reconnect
180 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 mid_entry->midState = MID_RETRY_NEEDED;
182 }
183 }
184 }
185 spin_unlock(&GlobalMid_Lock);
186 up(&server->tcpSem);
187
188 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
189 {
190 if(server->protocolType == IPV6) {
191 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
192 } else {
193 rc = ipv4_connect(&server->addr.sockAddr,
194 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700195 server->workstation_RFC1001_name,
196 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 }
198 if(rc) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700199 cFYI(1,("reconnect error %d",rc));
Steve French0cb766a2005-04-28 22:41:11 -0700200 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 } else {
202 atomic_inc(&tcpSesReconnectCount);
203 spin_lock(&GlobalMid_Lock);
204 if(server->tcpStatus != CifsExiting)
205 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700206 server->sequence_number = 0;
207 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 /* atomic_set(&server->inFlight,0);*/
209 wake_up(&server->response_q);
210 }
211 }
212 return rc;
213}
214
Steve Frenche4eb2952005-04-28 22:41:09 -0700215/*
216 return codes:
217 0 not a transact2, or all data present
218 >0 transact2 with that much data missing
219 -EINVAL = invalid transact2
220
221 */
222static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
223{
224 struct smb_t2_rsp * pSMBt;
225 int total_data_size;
226 int data_in_this_rsp;
227 int remaining;
228
229 if(pSMB->Command != SMB_COM_TRANSACTION2)
230 return 0;
231
232 /* check for plausible wct, bcc and t2 data and parm sizes */
233 /* check for parm and data offset going beyond end of smb */
234 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
235 cFYI(1,("invalid transact2 word count"));
236 return -EINVAL;
237 }
238
239 pSMBt = (struct smb_t2_rsp *)pSMB;
240
241 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
242 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
243
244 remaining = total_data_size - data_in_this_rsp;
245
246 if(remaining == 0)
247 return 0;
248 else if(remaining < 0) {
249 cFYI(1,("total data %d smaller than data in frame %d",
250 total_data_size, data_in_this_rsp));
251 return -EINVAL;
252 } else {
253 cFYI(1,("missing %d bytes from transact2, check next response",
254 remaining));
255 if(total_data_size > maxBufSize) {
256 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
257 total_data_size,maxBufSize));
258 return -EINVAL;
259 }
260 return remaining;
261 }
262}
263
264static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
265{
266 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
267 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
268 int total_data_size;
269 int total_in_buf;
270 int remaining;
271 int total_in_buf2;
272 char * data_area_of_target;
273 char * data_area_of_buf2;
274 __u16 byte_count;
275
276 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
277
278 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
279 cFYI(1,("total data sizes of primary and secondary t2 differ"));
280 }
281
282 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
283
284 remaining = total_data_size - total_in_buf;
285
286 if(remaining < 0)
287 return -EINVAL;
288
289 if(remaining == 0) /* nothing to do, ignore */
290 return 0;
291
292 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
293 if(remaining < total_in_buf2) {
294 cFYI(1,("transact2 2nd response contains too much data"));
295 }
296
297 /* find end of first SMB data area */
298 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
299 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
300 /* validate target area */
301
302 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
303 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
304
305 data_area_of_target += total_in_buf;
306
307 /* copy second buffer into end of first buffer */
308 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
309 total_in_buf += total_in_buf2;
310 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
311 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
312 byte_count += total_in_buf2;
313 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
314
Steve French70ca7342005-09-22 16:32:06 -0700315 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700316 byte_count += total_in_buf2;
317
318 /* BB also add check that we are not beyond maximum buffer size */
319
Steve French70ca7342005-09-22 16:32:06 -0700320 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700321
322 if(remaining == total_in_buf2) {
323 cFYI(1,("found the last secondary response"));
324 return 0; /* we are done */
325 } else /* more responses to go */
326 return 1;
327
328}
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330static int
331cifs_demultiplex_thread(struct TCP_Server_Info *server)
332{
333 int length;
334 unsigned int pdu_length, total_read;
335 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700336 struct smb_hdr *bigbuf = NULL;
337 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 struct msghdr smb_msg;
339 struct kvec iov;
340 struct socket *csocket = server->ssocket;
341 struct list_head *tmp;
342 struct cifsSesInfo *ses;
343 struct task_struct *task_to_wake = NULL;
344 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700345 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700346 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700347 int isMultiRsp;
348 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 daemonize("cifsd");
351 allow_signal(SIGKILL);
352 current->flags |= PF_MEMALLOC;
353 server->tsk = current; /* save process info to wake at shutdown */
354 cFYI(1, ("Demultiplex PID: %d", current->pid));
355 write_lock(&GlobalSMBSeslock);
356 atomic_inc(&tcpSesAllocCount);
357 length = tcpSesAllocCount.counter;
358 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700359 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 if(length > 1) {
361 mempool_resize(cifs_req_poolp,
362 length + cifs_min_rcv,
363 GFP_KERNEL);
364 }
365
366 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700367 if (try_to_freeze())
368 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700369 if (bigbuf == NULL) {
370 bigbuf = cifs_buf_get();
371 if(bigbuf == NULL) {
372 cERROR(1,("No memory for large SMB response"));
373 msleep(3000);
374 /* retry will check if exiting */
375 continue;
376 }
377 } else if(isLargeBuf) {
378 /* we are reusing a dirtry large buf, clear its start */
379 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700381
382 if (smallbuf == NULL) {
383 smallbuf = cifs_small_buf_get();
384 if(smallbuf == NULL) {
385 cERROR(1,("No memory for SMB response"));
386 msleep(1000);
387 /* retry will check if exiting */
388 continue;
389 }
390 /* beginning of smb buffer is cleared in our buf_get */
391 } else /* if existing small buf clear beginning */
392 memset(smallbuf, 0, sizeof (struct smb_hdr));
393
394 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700395 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700396 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 iov.iov_base = smb_buffer;
398 iov.iov_len = 4;
399 smb_msg.msg_control = NULL;
400 smb_msg.msg_controllen = 0;
401 length =
402 kernel_recvmsg(csocket, &smb_msg,
403 &iov, 1, 4, 0 /* BB see socket.h flags */);
404
405 if(server->tcpStatus == CifsExiting) {
406 break;
407 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French57337e42005-04-28 22:41:10 -0700408 cFYI(1,("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 cifs_reconnect(server);
410 cFYI(1,("call to reconnect done"));
411 csocket = server->ssocket;
412 continue;
413 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700414 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 allowing socket to clear and app threads to set
416 tcpStatus CifsNeedReconnect if server hung */
417 continue;
418 } else if (length <= 0) {
419 if(server->tcpStatus == CifsNew) {
Steve French57337e42005-04-28 22:41:10 -0700420 cFYI(1,("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700421 /* some servers kill the TCP session rather than
422 returning an SMB negprot error, in which
423 case reconnecting here is not going to help,
424 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 break;
426 }
427 if(length == -EINTR) {
428 cFYI(1,("cifsd thread killed"));
429 break;
430 }
Steve French57337e42005-04-28 22:41:10 -0700431 cFYI(1,("Reconnect after unexpected peek error %d",
432 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 cifs_reconnect(server);
434 csocket = server->ssocket;
435 wake_up(&server->response_q);
436 continue;
Steve French46810cb2005-04-28 22:41:09 -0700437 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700439 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 length));
441 cifs_reconnect(server);
442 csocket = server->ssocket;
443 wake_up(&server->response_q);
444 continue;
445 }
Steve French67010fb2005-04-28 22:41:09 -0700446
Steve French70ca7342005-09-22 16:32:06 -0700447 /* The right amount was read from socket - 4 bytes */
448 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700449
Steve French70ca7342005-09-22 16:32:06 -0700450 /* the first byte big endian of the length field,
451 is actually not part of the length but the type
452 with the most common, zero, as regular data */
453 temp = *((char *) smb_buffer);
454
455 /* Note that FC 1001 length is big endian on the wire,
456 but we convert it here so it is always manipulated
457 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700458 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700459 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700460
Steve French70ca7342005-09-22 16:32:06 -0700461 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
462
463 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700464 continue;
Steve French70ca7342005-09-22 16:32:06 -0700465 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700466 cFYI(1,("Good RFC 1002 session rsp"));
467 continue;
Steve French70ca7342005-09-22 16:32:06 -0700468 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve French46810cb2005-04-28 22:41:09 -0700469 /* we get this from Windows 98 instead of
470 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700471 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700472 pdu_length));
Steve French46810cb2005-04-28 22:41:09 -0700473 if(server->tcpStatus == CifsNew) {
474 /* if nack on negprot (rather than
475 ret of smb negprot error) reconnecting
476 not going to help, ret error to mount */
477 break;
478 } else {
479 /* give server a second to
480 clean up before reconnect attempt */
481 msleep(1000);
482 /* always try 445 first on reconnect
483 since we get NACK on some if we ever
484 connected to port 139 (the NACK is
485 since we do not begin with RFC1001
486 session initialize frame) */
487 server->addr.sockAddr.sin_port =
488 htons(CIFS_PORT);
489 cifs_reconnect(server);
490 csocket = server->ssocket;
491 wake_up(&server->response_q);
492 continue;
493 }
Steve French70ca7342005-09-22 16:32:06 -0700494 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700495 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700496 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
497 length);
Steve French46810cb2005-04-28 22:41:09 -0700498 cifs_reconnect(server);
499 csocket = server->ssocket;
500 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700501 }
502
503 /* else we have an SMB response */
504 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700505 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700506 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700507 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700508 cifs_reconnect(server);
509 csocket = server->ssocket;
510 wake_up(&server->response_q);
511 continue;
512 }
513
514 /* else length ok */
515 reconnect = 0;
516
517 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
518 isLargeBuf = TRUE;
519 memcpy(bigbuf, smallbuf, 4);
520 smb_buffer = bigbuf;
521 }
522 length = 0;
523 iov.iov_base = 4 + (char *)smb_buffer;
524 iov.iov_len = pdu_length;
525 for (total_read = 0; total_read < pdu_length;
526 total_read += length) {
527 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
528 pdu_length - total_read, 0);
529 if((server->tcpStatus == CifsExiting) ||
530 (length == -EINTR)) {
531 /* then will exit */
532 reconnect = 2;
533 break;
534 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700535 cifs_reconnect(server);
536 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700537 /* Reconnect wakes up rspns q */
538 /* Now we will reread sock */
539 reconnect = 1;
540 break;
541 } else if ((length == -ERESTARTSYS) ||
542 (length == -EAGAIN)) {
543 msleep(1); /* minimum sleep to prevent looping,
544 allowing socket to clear and app
545 threads to set tcpStatus
546 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700547 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 } else if (length <= 0) {
549 cERROR(1,("Received no data, expecting %d",
550 pdu_length - total_read));
551 cifs_reconnect(server);
552 csocket = server->ssocket;
553 reconnect = 1;
554 break;
Steve French46810cb2005-04-28 22:41:09 -0700555 }
556 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700557 if(reconnect == 2)
558 break;
559 else if(reconnect == 1)
560 continue;
561
562 length += 4; /* account for rfc1002 hdr */
563
564
565 dump_smb(smb_buffer, length);
566 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700567 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700568 continue;
569 }
570
571
572 task_to_wake = NULL;
573 spin_lock(&GlobalMid_Lock);
574 list_for_each(tmp, &server->pending_mid_q) {
575 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
576
577 if ((mid_entry->mid == smb_buffer->Mid) &&
578 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
579 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
581 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700582 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 if(mid_entry->resp_buf) {
584 /* merge response - fix up 1st*/
585 if(coalesce_t2(smb_buffer,
586 mid_entry->resp_buf)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 break;
588 } else {
589 /* all parts received */
590 goto multi_t2_fnd;
591 }
592 } else {
593 if(!isLargeBuf) {
594 cERROR(1,("1st trans2 resp needs bigbuf"));
595 /* BB maybe we can fix this up, switch
596 to already allocated large buffer? */
597 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700598 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 mid_entry->resp_buf =
600 smb_buffer;
601 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700602 bigbuf = NULL;
603 }
604 }
605 break;
606 }
607 mid_entry->resp_buf = smb_buffer;
608 if(isLargeBuf)
609 mid_entry->largeBuf = 1;
610 else
611 mid_entry->largeBuf = 0;
612multi_t2_fnd:
613 task_to_wake = mid_entry->tsk;
614 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700615#ifdef CONFIG_CIFS_STATS2
616 mid_entry->when_received = jiffies;
617#endif
Steve Frenche4eb2952005-04-28 22:41:09 -0700618 break;
619 }
620 }
621 spin_unlock(&GlobalMid_Lock);
622 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700623 /* Was previous buf put in mpx struct for multi-rsp? */
624 if(!isMultiRsp) {
625 /* smb buffer will be freed by user thread */
626 if(isLargeBuf) {
627 bigbuf = NULL;
628 } else
629 smallbuf = NULL;
630 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700631 wake_up_process(task_to_wake);
Steve French57337e42005-04-28 22:41:10 -0700632 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700633 && (isMultiRsp == FALSE)) {
634 cERROR(1, ("No task to wake, unknown frame rcvd!"));
Steve French70ca7342005-09-22 16:32:06 -0700635 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
636 sizeof(struct smb_hdr));
Steve Frenche4eb2952005-04-28 22:41:09 -0700637 }
638 } /* end while !EXITING */
639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 spin_lock(&GlobalMid_Lock);
641 server->tcpStatus = CifsExiting;
642 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700643 /* check if we have blocked requests that need to free */
644 /* Note that cifs_max_pending is normally 50, but
645 can be set at module install time to as little as two */
646 if(atomic_read(&server->inFlight) >= cifs_max_pending)
647 atomic_set(&server->inFlight, cifs_max_pending - 1);
648 /* We do not want to set the max_pending too low or we
649 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 spin_unlock(&GlobalMid_Lock);
651 /* Although there should not be any requests blocked on
652 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700653 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 to the same server - they now will see the session is in exit state
655 and get out of SendReceive. */
656 wake_up_all(&server->request_q);
657 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700658 msleep(125);
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 if(server->ssocket) {
661 sock_release(csocket);
662 server->ssocket = NULL;
663 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700664 /* buffer usuallly freed in free_mid - need to free it here on exit */
665 if (bigbuf != NULL)
666 cifs_buf_release(bigbuf);
667 if (smallbuf != NULL)
668 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
670 read_lock(&GlobalSMBSeslock);
671 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700672 /* loop through server session structures attached to this and
673 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 list_for_each(tmp, &GlobalSMBSessionList) {
675 ses =
676 list_entry(tmp, struct cifsSesInfo,
677 cifsSessionList);
678 if (ses->server == server) {
679 ses->status = CifsExiting;
680 ses->server = NULL;
681 }
682 }
683 read_unlock(&GlobalSMBSeslock);
684 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700685 /* although we can not zero the server struct pointer yet,
686 since there are active requests which may depnd on them,
687 mark the corresponding SMB sessions as exiting too */
688 list_for_each(tmp, &GlobalSMBSessionList) {
689 ses = list_entry(tmp, struct cifsSesInfo,
690 cifsSessionList);
691 if (ses->server == server) {
692 ses->status = CifsExiting;
693 }
694 }
695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 spin_lock(&GlobalMid_Lock);
697 list_for_each(tmp, &server->pending_mid_q) {
698 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
699 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
700 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700701 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 task_to_wake = mid_entry->tsk;
703 if(task_to_wake) {
704 wake_up_process(task_to_wake);
705 }
706 }
707 }
708 spin_unlock(&GlobalMid_Lock);
709 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700711 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 }
713
Steve Frenchf1914012005-08-18 09:37:34 -0700714 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 /* mpx threads have not exited yet give them
716 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700717 /* due to delays on oplock break requests, we need
718 to wait at least 45 seconds before giving up
719 on a request getting a response and going ahead
720 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700722 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 /* if threads still have not exited they are probably never
724 coming home not much else we can do but free the memory */
725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 write_lock(&GlobalSMBSeslock);
728 atomic_dec(&tcpSesAllocCount);
729 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700730
731 /* last chance to mark ses pointers invalid
732 if there are any pointing to this (e.g
733 if a crazy root user tried to kill cifsd
734 kernel thread explicitly this might happen) */
735 list_for_each(tmp, &GlobalSMBSessionList) {
736 ses = list_entry(tmp, struct cifsSesInfo,
737 cifsSessionList);
738 if (ses->server == server) {
739 ses->server = NULL;
740 }
741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700743
744 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if(length > 0) {
746 mempool_resize(cifs_req_poolp,
747 length + cifs_min_rcv,
748 GFP_KERNEL);
749 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700750
Steve Frenchf1914012005-08-18 09:37:34 -0700751 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return 0;
753}
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755static int
756cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
757{
758 char *value;
759 char *data;
760 unsigned int temp_len, i, j;
761 char separator[2];
762
763 separator[0] = ',';
764 separator[1] = 0;
765
766 memset(vol->source_rfc1001_name,0x20,15);
767 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
768 /* does not have to be a perfect mapping since the field is
769 informational, only used for servers that do not support
770 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700771 vol->source_rfc1001_name[i] =
772 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
774 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700775 /* null target name indicates to use *SMBSERVR default called name
776 if we end up sending RFC1001 session initialize */
777 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 vol->linux_uid = current->uid; /* current->euid instead? */
779 vol->linux_gid = current->gid;
780 vol->dir_mode = S_IRWXUGO;
781 /* 2767 perms indicate mandatory locking support */
782 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
783
784 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
785 vol->rw = TRUE;
Steve Frenchbf820672005-12-01 22:32:42 -0800786 vol->ntlm = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700787 /* default is always to request posix paths. */
788 vol->posix_paths = 1;
789
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (!options)
791 return 1;
792
793 if(strncmp(options,"sep=",4) == 0) {
794 if(options[4] != 0) {
795 separator[0] = options[4];
796 options += 5;
797 } else {
798 cFYI(1,("Null separator not allowed"));
799 }
800 }
801
802 while ((data = strsep(&options, separator)) != NULL) {
803 if (!*data)
804 continue;
805 if ((value = strchr(data, '=')) != NULL)
806 *value++ = '\0';
807
808 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
809 vol->no_xattr = 0;
810 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
811 vol->no_xattr = 1;
812 } else if (strnicmp(data, "user", 4) == 0) {
813 if (!value || !*value) {
814 printk(KERN_WARNING
815 "CIFS: invalid or missing username\n");
816 return 1; /* needs_arg; */
817 }
818 if (strnlen(value, 200) < 200) {
819 vol->username = value;
820 } else {
821 printk(KERN_WARNING "CIFS: username too long\n");
822 return 1;
823 }
824 } else if (strnicmp(data, "pass", 4) == 0) {
825 if (!value) {
826 vol->password = NULL;
827 continue;
828 } else if(value[0] == 0) {
829 /* check if string begins with double comma
830 since that would mean the password really
831 does start with a comma, and would not
832 indicate an empty string */
833 if(value[1] != separator[0]) {
834 vol->password = NULL;
835 continue;
836 }
837 }
838 temp_len = strlen(value);
839 /* removed password length check, NTLM passwords
840 can be arbitrarily long */
841
842 /* if comma in password, the string will be
843 prematurely null terminated. Commas in password are
844 specified across the cifs mount interface by a double
845 comma ie ,, and a comma used as in other cases ie ','
846 as a parameter delimiter/separator is single and due
847 to the strsep above is temporarily zeroed. */
848
849 /* NB: password legally can have multiple commas and
850 the only illegal character in a password is null */
851
Steve French09d1db52005-04-28 22:41:08 -0700852 if ((value[temp_len] == 0) &&
853 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 /* reinsert comma */
855 value[temp_len] = separator[0];
856 temp_len+=2; /* move after the second comma */
857 while(value[temp_len] != 0) {
858 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700859 if (value[temp_len+1] ==
860 separator[0]) {
861 /* skip second comma */
862 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 } else {
864 /* single comma indicating start
865 of next parm */
866 break;
867 }
868 }
869 temp_len++;
870 }
871 if(value[temp_len] == 0) {
872 options = NULL;
873 } else {
874 value[temp_len] = 0;
875 /* point option to start of next parm */
876 options = value + temp_len + 1;
877 }
878 /* go from value to value + temp_len condensing
879 double commas to singles. Note that this ends up
880 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700881 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700882 if(vol->password == NULL) {
883 printk("CIFS: no memory for pass\n");
884 return 1;
885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 for(i=0,j=0;i<temp_len;i++,j++) {
887 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700888 if(value[i] == separator[0]
889 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 /* skip second comma */
891 i++;
892 }
893 }
894 vol->password[j] = 0;
895 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700896 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700897 if(vol->password == NULL) {
898 printk("CIFS: no memory for pass\n");
899 return 1;
900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 strcpy(vol->password, value);
902 }
903 } else if (strnicmp(data, "ip", 2) == 0) {
904 if (!value || !*value) {
905 vol->UNCip = NULL;
906 } else if (strnlen(value, 35) < 35) {
907 vol->UNCip = value;
908 } else {
909 printk(KERN_WARNING "CIFS: ip address too long\n");
910 return 1;
911 }
Steve Frenchbf820672005-12-01 22:32:42 -0800912 } else if (strnicmp(data, "sec", 3) == 0) {
913 if (!value || !*value) {
914 cERROR(1,("no security value specified"));
915 continue;
916 } else if (strnicmp(value, "krb5i", 5) == 0) {
917 vol->sign = 1;
918 vol->krb5 = 1;
919 } else if (strnicmp(value, "krb5p", 5) == 0) {
920 /* vol->seal = 1;
921 vol->krb5 = 1; */
922 cERROR(1,("Krb5 cifs privacy not supported"));
923 return 1;
924 } else if (strnicmp(value, "krb5", 4) == 0) {
925 vol->krb5 = 1;
926 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
927 vol->ntlmv2 = 1;
928 vol->sign = 1;
929 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
930 vol->ntlmv2 = 1;
931 } else if (strnicmp(value, "ntlmi", 5) == 0) {
932 vol->ntlm = 1;
933 vol->sign = 1;
934 } else if (strnicmp(value, "ntlm", 4) == 0) {
935 /* ntlm is default so can be turned off too */
936 vol->ntlm = 1;
937 } else if (strnicmp(value, "nontlm", 6) == 0) {
938 vol->ntlm = 0;
939 } else if (strnicmp(value, "none", 4) == 0) {
940 vol->nullauth = 1;
941 } else {
942 cERROR(1,("bad security option: %s", value));
943 return 1;
944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 } else if ((strnicmp(data, "unc", 3) == 0)
946 || (strnicmp(data, "target", 6) == 0)
947 || (strnicmp(data, "path", 4) == 0)) {
948 if (!value || !*value) {
949 printk(KERN_WARNING
950 "CIFS: invalid path to network resource\n");
951 return 1; /* needs_arg; */
952 }
953 if ((temp_len = strnlen(value, 300)) < 300) {
954 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
955 if(vol->UNC == NULL)
956 return 1;
957 strcpy(vol->UNC,value);
958 if (strncmp(vol->UNC, "//", 2) == 0) {
959 vol->UNC[0] = '\\';
960 vol->UNC[1] = '\\';
961 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
962 printk(KERN_WARNING
963 "CIFS: UNC Path does not begin with // or \\\\ \n");
964 return 1;
965 }
966 } else {
967 printk(KERN_WARNING "CIFS: UNC name too long\n");
968 return 1;
969 }
970 } else if ((strnicmp(data, "domain", 3) == 0)
971 || (strnicmp(data, "workgroup", 5) == 0)) {
972 if (!value || !*value) {
973 printk(KERN_WARNING "CIFS: invalid domain name\n");
974 return 1; /* needs_arg; */
975 }
976 /* BB are there cases in which a comma can be valid in
977 a domain name and need special handling? */
978 if (strnlen(value, 65) < 65) {
979 vol->domainname = value;
980 cFYI(1, ("Domain name set"));
981 } else {
982 printk(KERN_WARNING "CIFS: domain name too long\n");
983 return 1;
984 }
985 } else if (strnicmp(data, "iocharset", 9) == 0) {
986 if (!value || !*value) {
987 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
988 return 1; /* needs_arg; */
989 }
990 if (strnlen(value, 65) < 65) {
991 if(strnicmp(value,"default",7))
992 vol->iocharset = value;
993 /* if iocharset not set load_nls_default used by caller */
994 cFYI(1, ("iocharset set to %s",value));
995 } else {
996 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
997 return 1;
998 }
999 } else if (strnicmp(data, "uid", 3) == 0) {
1000 if (value && *value) {
1001 vol->linux_uid =
1002 simple_strtoul(value, &value, 0);
1003 }
1004 } else if (strnicmp(data, "gid", 3) == 0) {
1005 if (value && *value) {
1006 vol->linux_gid =
1007 simple_strtoul(value, &value, 0);
1008 }
1009 } else if (strnicmp(data, "file_mode", 4) == 0) {
1010 if (value && *value) {
1011 vol->file_mode =
1012 simple_strtoul(value, &value, 0);
1013 }
1014 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1015 if (value && *value) {
1016 vol->dir_mode =
1017 simple_strtoul(value, &value, 0);
1018 }
1019 } else if (strnicmp(data, "dirmode", 4) == 0) {
1020 if (value && *value) {
1021 vol->dir_mode =
1022 simple_strtoul(value, &value, 0);
1023 }
1024 } else if (strnicmp(data, "port", 4) == 0) {
1025 if (value && *value) {
1026 vol->port =
1027 simple_strtoul(value, &value, 0);
1028 }
1029 } else if (strnicmp(data, "rsize", 5) == 0) {
1030 if (value && *value) {
1031 vol->rsize =
1032 simple_strtoul(value, &value, 0);
1033 }
1034 } else if (strnicmp(data, "wsize", 5) == 0) {
1035 if (value && *value) {
1036 vol->wsize =
1037 simple_strtoul(value, &value, 0);
1038 }
1039 } else if (strnicmp(data, "sockopt", 5) == 0) {
1040 if (value && *value) {
1041 vol->sockopt =
1042 simple_strtoul(value, &value, 0);
1043 }
1044 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1045 if (!value || !*value || (*value == ' ')) {
1046 cFYI(1,("invalid (empty) netbiosname specified"));
1047 } else {
1048 memset(vol->source_rfc1001_name,0x20,15);
1049 for(i=0;i<15;i++) {
1050 /* BB are there cases in which a comma can be
1051 valid in this workstation netbios name (and need
1052 special handling)? */
1053
1054 /* We do not uppercase netbiosname for user */
1055 if (value[i]==0)
1056 break;
1057 else
1058 vol->source_rfc1001_name[i] = value[i];
1059 }
1060 /* The string has 16th byte zero still from
1061 set at top of the function */
1062 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001063 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1064 }
1065 } else if (strnicmp(data, "servern", 7) == 0) {
1066 /* servernetbiosname specified override *SMBSERVER */
1067 if (!value || !*value || (*value == ' ')) {
1068 cFYI(1,("empty server netbiosname specified"));
1069 } else {
1070 /* last byte, type, is 0x20 for servr type */
1071 memset(vol->target_rfc1001_name,0x20,16);
1072
1073 for(i=0;i<15;i++) {
1074 /* BB are there cases in which a comma can be
1075 valid in this workstation netbios name (and need
1076 special handling)? */
1077
1078 /* user or mount helper must uppercase netbiosname */
1079 if (value[i]==0)
1080 break;
1081 else
1082 vol->target_rfc1001_name[i] = value[i];
1083 }
1084 /* The string has 16th byte zero still from
1085 set at top of the function */
1086 if((i==15) && (value[i] != 0))
1087 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
1089 } else if (strnicmp(data, "credentials", 4) == 0) {
1090 /* ignore */
1091 } else if (strnicmp(data, "version", 3) == 0) {
1092 /* ignore */
1093 } else if (strnicmp(data, "guest",5) == 0) {
1094 /* ignore */
1095 } else if (strnicmp(data, "rw", 2) == 0) {
1096 vol->rw = TRUE;
1097 } else if ((strnicmp(data, "suid", 4) == 0) ||
1098 (strnicmp(data, "nosuid", 6) == 0) ||
1099 (strnicmp(data, "exec", 4) == 0) ||
1100 (strnicmp(data, "noexec", 6) == 0) ||
1101 (strnicmp(data, "nodev", 5) == 0) ||
1102 (strnicmp(data, "noauto", 6) == 0) ||
1103 (strnicmp(data, "dev", 3) == 0)) {
1104 /* The mount tool or mount.cifs helper (if present)
1105 uses these opts to set flags, and the flags are read
1106 by the kernel vfs layer before we get here (ie
1107 before read super) so there is no point trying to
1108 parse these options again and set anything and it
1109 is ok to just ignore them */
1110 continue;
1111 } else if (strnicmp(data, "ro", 2) == 0) {
1112 vol->rw = FALSE;
1113 } else if (strnicmp(data, "hard", 4) == 0) {
1114 vol->retry = 1;
1115 } else if (strnicmp(data, "soft", 4) == 0) {
1116 vol->retry = 0;
1117 } else if (strnicmp(data, "perm", 4) == 0) {
1118 vol->noperm = 0;
1119 } else if (strnicmp(data, "noperm", 6) == 0) {
1120 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001121 } else if (strnicmp(data, "mapchars", 8) == 0) {
1122 vol->remap = 1;
1123 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1124 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001125 } else if (strnicmp(data, "sfu", 3) == 0) {
1126 vol->sfu_emul = 1;
1127 } else if (strnicmp(data, "nosfu", 5) == 0) {
1128 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001129 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1130 vol->posix_paths = 1;
1131 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1132 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001133 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1134 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001135 vol->nocase = 1;
1136 } else if (strnicmp(data, "brl", 3) == 0) {
1137 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001138 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001139 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001140 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001141 /* turn off mandatory locking in mode
1142 if remote locking is turned off since the
1143 local vfs will do advisory */
1144 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1145 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 } else if (strnicmp(data, "setuids", 7) == 0) {
1147 vol->setuids = 1;
1148 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1149 vol->setuids = 0;
1150 } else if (strnicmp(data, "nohard", 6) == 0) {
1151 vol->retry = 0;
1152 } else if (strnicmp(data, "nosoft", 6) == 0) {
1153 vol->retry = 1;
1154 } else if (strnicmp(data, "nointr", 6) == 0) {
1155 vol->intr = 0;
1156 } else if (strnicmp(data, "intr", 4) == 0) {
1157 vol->intr = 1;
1158 } else if (strnicmp(data, "serverino",7) == 0) {
1159 vol->server_ino = 1;
1160 } else if (strnicmp(data, "noserverino",9) == 0) {
1161 vol->server_ino = 0;
1162 } else if (strnicmp(data, "acl",3) == 0) {
1163 vol->no_psx_acl = 0;
1164 } else if (strnicmp(data, "noacl",5) == 0) {
1165 vol->no_psx_acl = 1;
1166 } else if (strnicmp(data, "direct",6) == 0) {
1167 vol->direct_io = 1;
1168 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1169 vol->direct_io = 1;
1170 } else if (strnicmp(data, "in6_addr",8) == 0) {
1171 if (!value || !*value) {
1172 vol->in6_addr = NULL;
1173 } else if (strnlen(value, 49) == 48) {
1174 vol->in6_addr = value;
1175 } else {
1176 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1177 return 1;
1178 }
1179 } else if (strnicmp(data, "noac", 4) == 0) {
1180 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1181 } else
1182 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1183 }
1184 if (vol->UNC == NULL) {
1185 if(devname == NULL) {
1186 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1187 return 1;
1188 }
1189 if ((temp_len = strnlen(devname, 300)) < 300) {
1190 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1191 if(vol->UNC == NULL)
1192 return 1;
1193 strcpy(vol->UNC,devname);
1194 if (strncmp(vol->UNC, "//", 2) == 0) {
1195 vol->UNC[0] = '\\';
1196 vol->UNC[1] = '\\';
1197 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1198 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1199 return 1;
1200 }
1201 } else {
1202 printk(KERN_WARNING "CIFS: UNC name too long\n");
1203 return 1;
1204 }
1205 }
1206 if(vol->UNCip == NULL)
1207 vol->UNCip = &vol->UNC[2];
1208
1209 return 0;
1210}
1211
1212static struct cifsSesInfo *
1213cifs_find_tcp_session(struct in_addr * target_ip_addr,
1214 struct in6_addr *target_ip6_addr,
1215 char *userName, struct TCP_Server_Info **psrvTcp)
1216{
1217 struct list_head *tmp;
1218 struct cifsSesInfo *ses;
1219 *psrvTcp = NULL;
1220 read_lock(&GlobalSMBSeslock);
1221
1222 list_for_each(tmp, &GlobalSMBSessionList) {
1223 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1224 if (ses->server) {
1225 if((target_ip_addr &&
1226 (ses->server->addr.sockAddr.sin_addr.s_addr
1227 == target_ip_addr->s_addr)) || (target_ip6_addr
1228 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1229 target_ip6_addr,sizeof(*target_ip6_addr)))){
1230 /* BB lock server and tcp session and increment use count here?? */
1231 *psrvTcp = ses->server; /* found a match on the TCP session */
1232 /* BB check if reconnection needed */
1233 if (strncmp
1234 (ses->userName, userName,
1235 MAX_USERNAME_SIZE) == 0){
1236 read_unlock(&GlobalSMBSeslock);
1237 return ses; /* found exact match on both tcp and SMB sessions */
1238 }
1239 }
1240 }
1241 /* else tcp and smb sessions need reconnection */
1242 }
1243 read_unlock(&GlobalSMBSeslock);
1244 return NULL;
1245}
1246
1247static struct cifsTconInfo *
1248find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1249{
1250 struct list_head *tmp;
1251 struct cifsTconInfo *tcon;
1252
1253 read_lock(&GlobalSMBSeslock);
1254 list_for_each(tmp, &GlobalTreeConnectionList) {
1255 cFYI(1, ("Next tcon - "));
1256 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1257 if (tcon->ses) {
1258 if (tcon->ses->server) {
1259 cFYI(1,
1260 (" old ip addr: %x == new ip %x ?",
1261 tcon->ses->server->addr.sockAddr.sin_addr.
1262 s_addr, new_target_ip_addr));
1263 if (tcon->ses->server->addr.sockAddr.sin_addr.
1264 s_addr == new_target_ip_addr) {
1265 /* BB lock tcon and server and tcp session and increment use count here? */
1266 /* found a match on the TCP session */
1267 /* BB check if reconnection needed */
1268 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1269 tcon->treeName, uncName));
1270 if (strncmp
1271 (tcon->treeName, uncName,
1272 MAX_TREE_SIZE) == 0) {
1273 cFYI(1,
1274 ("Matched UNC, old user: %s == new: %s ?",
1275 tcon->treeName, uncName));
1276 if (strncmp
1277 (tcon->ses->userName,
1278 userName,
1279 MAX_USERNAME_SIZE) == 0) {
1280 read_unlock(&GlobalSMBSeslock);
1281 return tcon;/* also matched user (smb session)*/
1282 }
1283 }
1284 }
1285 }
1286 }
1287 }
1288 read_unlock(&GlobalSMBSeslock);
1289 return NULL;
1290}
1291
1292int
1293connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001294 const char *old_path, const struct nls_table *nls_codepage,
1295 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
1297 unsigned char *referrals = NULL;
1298 unsigned int num_referrals;
1299 int rc = 0;
1300
1301 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001302 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
1304 /* BB Add in code to: if valid refrl, if not ip address contact
1305 the helper that resolves tcp names, mount to it, try to
1306 tcon to it unmount it if fail */
1307
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001308 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
1310 return rc;
1311}
1312
1313int
1314get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1315 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001316 unsigned int *pnum_referrals,
1317 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
1319 char *temp_unc;
1320 int rc = 0;
1321
1322 *pnum_referrals = 0;
1323
1324 if (pSesInfo->ipc_tid == 0) {
1325 temp_unc = kmalloc(2 /* for slashes */ +
1326 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1327 + 1 + 4 /* slash IPC$ */ + 2,
1328 GFP_KERNEL);
1329 if (temp_unc == NULL)
1330 return -ENOMEM;
1331 temp_unc[0] = '\\';
1332 temp_unc[1] = '\\';
1333 strcpy(temp_unc + 2, pSesInfo->serverName);
1334 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1335 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1336 cFYI(1,
1337 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1338 kfree(temp_unc);
1339 }
1340 if (rc == 0)
1341 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001342 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344 return rc;
1345}
1346
1347/* See RFC1001 section 14 on representation of Netbios names */
1348static void rfc1002mangle(char * target,char * source, unsigned int length)
1349{
1350 unsigned int i,j;
1351
1352 for(i=0,j=0;i<(length);i++) {
1353 /* mask a nibble at a time and encode */
1354 target[j] = 'A' + (0x0F & (source[i] >> 4));
1355 target[j+1] = 'A' + (0x0F & source[i]);
1356 j+=2;
1357 }
1358
1359}
1360
1361
1362static int
1363ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001364 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
1366 int rc = 0;
1367 int connected = 0;
1368 __be16 orig_port = 0;
1369
1370 if(*csocket == NULL) {
1371 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1372 if (rc < 0) {
1373 cERROR(1, ("Error %d creating socket",rc));
1374 *csocket = NULL;
1375 return rc;
1376 } else {
1377 /* BB other socket options to set KEEPALIVE, NODELAY? */
1378 cFYI(1,("Socket created"));
1379 (*csocket)->sk->sk_allocation = GFP_NOFS;
1380 }
1381 }
1382
1383 psin_server->sin_family = AF_INET;
1384 if(psin_server->sin_port) { /* user overrode default port */
1385 rc = (*csocket)->ops->connect(*csocket,
1386 (struct sockaddr *) psin_server,
1387 sizeof (struct sockaddr_in),0);
1388 if (rc >= 0)
1389 connected = 1;
1390 }
1391
1392 if(!connected) {
1393 /* save original port so we can retry user specified port
1394 later if fall back ports fail this time */
1395 orig_port = psin_server->sin_port;
1396
1397 /* do not retry on the same port we just failed on */
1398 if(psin_server->sin_port != htons(CIFS_PORT)) {
1399 psin_server->sin_port = htons(CIFS_PORT);
1400
1401 rc = (*csocket)->ops->connect(*csocket,
1402 (struct sockaddr *) psin_server,
1403 sizeof (struct sockaddr_in),0);
1404 if (rc >= 0)
1405 connected = 1;
1406 }
1407 }
1408 if (!connected) {
1409 psin_server->sin_port = htons(RFC1001_PORT);
1410 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1411 psin_server, sizeof (struct sockaddr_in),0);
1412 if (rc >= 0)
1413 connected = 1;
1414 }
1415
1416 /* give up here - unless we want to retry on different
1417 protocol families some day */
1418 if (!connected) {
1419 if(orig_port)
1420 psin_server->sin_port = orig_port;
1421 cFYI(1,("Error %d connecting to server via ipv4",rc));
1422 sock_release(*csocket);
1423 *csocket = NULL;
1424 return rc;
1425 }
1426 /* Eventually check for other socket options to change from
1427 the default. sock_setsockopt not used because it expects
1428 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001429 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1430 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001432 /* make the bufsizes depend on wsize/rsize and max requests */
1433 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1434 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1435 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1436 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
1438 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1440 /* some servers require RFC1001 sessinit before sending
1441 negprot - BB check reconnection in case where second
1442 sessinit is sent but no second negprot */
1443 struct rfc1002_session_packet * ses_init_buf;
1444 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001445 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 if(ses_init_buf) {
1447 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001448 if(target_name && (target_name[0] != 0)) {
1449 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1450 target_name, 16);
1451 } else {
1452 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1453 DEFAULT_CIFS_CALLED_NAME,16);
1454 }
1455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 ses_init_buf->trailer.session_req.calling_len = 32;
1457 /* calling name ends in null (byte 16) from old smb
1458 convention. */
1459 if(netbios_name && (netbios_name[0] !=0)) {
1460 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1461 netbios_name,16);
1462 } else {
1463 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1464 "LINUX_CIFS_CLNT",16);
1465 }
1466 ses_init_buf->trailer.session_req.scope1 = 0;
1467 ses_init_buf->trailer.session_req.scope2 = 0;
1468 smb_buf = (struct smb_hdr *)ses_init_buf;
1469 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1470 smb_buf->smb_buf_length = 0x81000044;
1471 rc = smb_send(*csocket, smb_buf, 0x44,
1472 (struct sockaddr *)psin_server);
1473 kfree(ses_init_buf);
1474 }
1475 /* else the negprot may still work without this
1476 even though malloc failed */
1477
1478 }
1479
1480 return rc;
1481}
1482
1483static int
1484ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1485{
1486 int rc = 0;
1487 int connected = 0;
1488 __be16 orig_port = 0;
1489
1490 if(*csocket == NULL) {
1491 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1492 if (rc < 0) {
1493 cERROR(1, ("Error %d creating ipv6 socket",rc));
1494 *csocket = NULL;
1495 return rc;
1496 } else {
1497 /* BB other socket options to set KEEPALIVE, NODELAY? */
1498 cFYI(1,("ipv6 Socket created"));
1499 (*csocket)->sk->sk_allocation = GFP_NOFS;
1500 }
1501 }
1502
1503 psin_server->sin6_family = AF_INET6;
1504
1505 if(psin_server->sin6_port) { /* user overrode default port */
1506 rc = (*csocket)->ops->connect(*csocket,
1507 (struct sockaddr *) psin_server,
1508 sizeof (struct sockaddr_in6),0);
1509 if (rc >= 0)
1510 connected = 1;
1511 }
1512
1513 if(!connected) {
1514 /* save original port so we can retry user specified port
1515 later if fall back ports fail this time */
1516
1517 orig_port = psin_server->sin6_port;
1518 /* do not retry on the same port we just failed on */
1519 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1520 psin_server->sin6_port = htons(CIFS_PORT);
1521
1522 rc = (*csocket)->ops->connect(*csocket,
1523 (struct sockaddr *) psin_server,
1524 sizeof (struct sockaddr_in6),0);
1525 if (rc >= 0)
1526 connected = 1;
1527 }
1528 }
1529 if (!connected) {
1530 psin_server->sin6_port = htons(RFC1001_PORT);
1531 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1532 psin_server, sizeof (struct sockaddr_in6),0);
1533 if (rc >= 0)
1534 connected = 1;
1535 }
1536
1537 /* give up here - unless we want to retry on different
1538 protocol families some day */
1539 if (!connected) {
1540 if(orig_port)
1541 psin_server->sin6_port = orig_port;
1542 cFYI(1,("Error %d connecting to server via ipv6",rc));
1543 sock_release(*csocket);
1544 *csocket = NULL;
1545 return rc;
1546 }
1547 /* Eventually check for other socket options to change from
1548 the default. sock_setsockopt not used because it expects
1549 user space buffer */
1550 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1551
1552 return rc;
1553}
1554
1555int
1556cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1557 char *mount_data, const char *devname)
1558{
1559 int rc = 0;
1560 int xid;
1561 int address_type = AF_INET;
1562 struct socket *csocket = NULL;
1563 struct sockaddr_in sin_server;
1564 struct sockaddr_in6 sin_server6;
1565 struct smb_vol volume_info;
1566 struct cifsSesInfo *pSesInfo = NULL;
1567 struct cifsSesInfo *existingCifsSes = NULL;
1568 struct cifsTconInfo *tcon = NULL;
1569 struct TCP_Server_Info *srvTcp = NULL;
1570
1571 xid = GetXid();
1572
1573/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1574
1575 memset(&volume_info,0,sizeof(struct smb_vol));
1576 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001577 kfree(volume_info.UNC);
1578 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 FreeXid(xid);
1580 return -EINVAL;
1581 }
1582
1583 if (volume_info.username) {
1584 /* BB fixme parse for domain name here */
1585 cFYI(1, ("Username: %s ", volume_info.username));
1586
1587 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001588 cifserror("No username specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 /* In userspace mount helper we can get user name from alternate
1590 locations such as env variables and files on disk */
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 if (volume_info.UNCip && volume_info.UNC) {
1598 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1599
1600 if(rc <= 0) {
1601 /* not ipv4 address, try ipv6 */
1602 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1603 if(rc > 0)
1604 address_type = AF_INET6;
1605 } else {
1606 address_type = AF_INET;
1607 }
1608
1609 if(rc <= 0) {
1610 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001611 kfree(volume_info.UNC);
1612 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 FreeXid(xid);
1614 return -EINVAL;
1615 }
1616
1617 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1618 /* success */
1619 rc = 0;
1620 } else if (volume_info.UNCip){
1621 /* BB using ip addr as server name connect to the DFS root below */
1622 cERROR(1,("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001623 kfree(volume_info.UNC);
1624 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 FreeXid(xid);
1626 return -EINVAL;
1627 } else /* which servers DFS root would we conect to */ {
1628 cERROR(1,
Steve Frenchbf820672005-12-01 22:32:42 -08001629 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001630 kfree(volume_info.UNC);
1631 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 FreeXid(xid);
1633 return -EINVAL;
1634 }
1635
1636 /* this is needed for ASCII cp to Unicode converts */
1637 if(volume_info.iocharset == NULL) {
1638 cifs_sb->local_nls = load_nls_default();
1639 /* load_nls_default can not return null */
1640 } else {
1641 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1642 if(cifs_sb->local_nls == NULL) {
1643 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001644 kfree(volume_info.UNC);
1645 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 FreeXid(xid);
1647 return -ELIBACC;
1648 }
1649 }
1650
1651 if(address_type == AF_INET)
1652 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1653 NULL /* no ipv6 addr */,
1654 volume_info.username, &srvTcp);
1655 else if(address_type == AF_INET6)
1656 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1657 &sin_server6.sin6_addr,
1658 volume_info.username, &srvTcp);
1659 else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001660 kfree(volume_info.UNC);
1661 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 FreeXid(xid);
1663 return -EINVAL;
1664 }
1665
1666
1667 if (srvTcp) {
Steve Frenchbf820672005-12-01 22:32:42 -08001668 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 } else { /* create socket */
1670 if(volume_info.port)
1671 sin_server.sin_port = htons(volume_info.port);
1672 else
1673 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001674 rc = ipv4_connect(&sin_server,&csocket,
1675 volume_info.source_rfc1001_name,
1676 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 if (rc < 0) {
1678 cERROR(1,
1679 ("Error connecting to IPv4 socket. Aborting operation"));
1680 if(csocket != NULL)
1681 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001682 kfree(volume_info.UNC);
1683 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 FreeXid(xid);
1685 return rc;
1686 }
1687
1688 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1689 if (srvTcp == NULL) {
1690 rc = -ENOMEM;
1691 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001692 kfree(volume_info.UNC);
1693 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 FreeXid(xid);
1695 return rc;
1696 } else {
1697 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1698 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1699 atomic_set(&srvTcp->inFlight,0);
1700 /* BB Add code for ipv6 case too */
1701 srvTcp->ssocket = csocket;
1702 srvTcp->protocolType = IPV4;
1703 init_waitqueue_head(&srvTcp->response_q);
1704 init_waitqueue_head(&srvTcp->request_q);
1705 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1706 /* at this point we are the only ones with the pointer
1707 to the struct since the kernel thread not created yet
1708 so no need to spinlock this init of tcpStatus */
1709 srvTcp->tcpStatus = CifsNew;
1710 init_MUTEX(&srvTcp->tcpSem);
1711 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1712 CLONE_FS | CLONE_FILES | CLONE_VM);
1713 if(rc < 0) {
1714 rc = -ENOMEM;
1715 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001716 kfree(volume_info.UNC);
1717 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 FreeXid(xid);
1719 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001720 }
1721 wait_for_completion(&cifsd_complete);
1722 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001724 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001725 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 }
1727 }
1728
1729 if (existingCifsSes) {
1730 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001731 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001732 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 /* volume_info.UNC freed at end of function */
1734 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001735 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 pSesInfo = sesInfoAlloc();
1737 if (pSesInfo == NULL)
1738 rc = -ENOMEM;
1739 else {
1740 pSesInfo->server = srvTcp;
1741 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1742 NIPQUAD(sin_server.sin_addr.s_addr));
1743 }
1744
1745 if (!rc){
1746 /* volume_info.password freed at unmount */
1747 if (volume_info.password)
1748 pSesInfo->password = volume_info.password;
1749 if (volume_info.username)
1750 strncpy(pSesInfo->userName,
1751 volume_info.username,MAX_USERNAME_SIZE);
1752 if (volume_info.domainname)
1753 strncpy(pSesInfo->domainName,
1754 volume_info.domainname,MAX_USERNAME_SIZE);
1755 pSesInfo->linux_uid = volume_info.linux_uid;
1756 down(&pSesInfo->sesSem);
1757 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1758 up(&pSesInfo->sesSem);
1759 if(!rc)
1760 atomic_inc(&srvTcp->socketUseCount);
1761 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001762 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 }
1764
1765 /* search for existing tcon to this server share */
1766 if (!rc) {
Steve French0ae0efa2005-10-10 10:57:19 -07001767 if(volume_info.rsize > CIFSMaxBufSize) {
1768 cERROR(1,("rsize %d too large, using MaxBufSize",
1769 volume_info.rsize));
1770 cifs_sb->rsize = CIFSMaxBufSize;
1771 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001773 else /* default */
1774 cifs_sb->rsize = CIFSMaxBufSize;
1775
1776 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1777 cERROR(1,("wsize %d too large using 4096 instead",
1778 volume_info.wsize));
1779 cifs_sb->wsize = 4096;
1780 } else if(volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 cifs_sb->wsize = volume_info.wsize;
1782 else
1783 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1784 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
Steve French6b8edfe2005-08-23 20:26:03 -07001785 cifs_sb->rsize = PAGE_CACHE_SIZE;
1786 /* Windows ME does this */
1787 cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 }
1789 cifs_sb->mnt_uid = volume_info.linux_uid;
1790 cifs_sb->mnt_gid = volume_info.linux_gid;
1791 cifs_sb->mnt_file_mode = volume_info.file_mode;
1792 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1793 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1794
1795 if(volume_info.noperm)
1796 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1797 if(volume_info.setuids)
1798 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1799 if(volume_info.server_ino)
1800 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001801 if(volume_info.remap)
1802 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 if(volume_info.no_xattr)
1804 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001805 if(volume_info.sfu_emul)
1806 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001807 if(volume_info.nobrl)
1808 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001811 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1813 }
1814
1815 tcon =
1816 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1817 volume_info.username);
1818 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08001819 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 /* we can have only one retry value for a connection
1821 to a share so for resources mounted more than once
1822 to the same server share the last value passed in
1823 for the retry flag is used */
1824 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001825 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 } else {
1827 tcon = tconInfoAlloc();
1828 if (tcon == NULL)
1829 rc = -ENOMEM;
1830 else {
1831 /* check for null share name ie connect to dfs root */
1832
1833 /* BB check if this works for exactly length three strings */
1834 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1835 && (strchr(volume_info.UNC + 3, '/') ==
1836 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001837 rc = connect_to_dfs_path(xid, pSesInfo,
1838 "", cifs_sb->local_nls,
1839 cifs_sb->mnt_cifs_flags &
1840 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001841 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 FreeXid(xid);
1843 return -ENODEV;
1844 } else {
1845 rc = CIFSTCon(xid, pSesInfo,
1846 volume_info.UNC,
1847 tcon, cifs_sb->local_nls);
1848 cFYI(1, ("CIFS Tcon rc = %d", rc));
1849 }
1850 if (!rc) {
1851 atomic_inc(&pSesInfo->inUse);
1852 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001853 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 }
1855 }
1856 }
1857 }
1858 if(pSesInfo) {
1859 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1860 sb->s_maxbytes = (u64) 1 << 63;
1861 } else
1862 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1863 }
1864
1865 sb->s_time_gran = 100;
1866
1867/* on error free sesinfo and tcon struct if needed */
1868 if (rc) {
1869 /* if session setup failed, use count is zero but
1870 we still need to free cifsd thread */
1871 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1872 spin_lock(&GlobalMid_Lock);
1873 srvTcp->tcpStatus = CifsExiting;
1874 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001875 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001877 wait_for_completion(&cifsd_complete);
1878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 }
1880 /* If find_unc succeeded then rc == 0 so we can not end */
1881 if (tcon) /* up accidently freeing someone elses tcon struct */
1882 tconInfoFree(tcon);
1883 if (existingCifsSes == NULL) {
1884 if (pSesInfo) {
1885 if ((pSesInfo->server) &&
1886 (pSesInfo->status == CifsGood)) {
1887 int temp_rc;
1888 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1889 /* if the socketUseCount is now zero */
1890 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001891 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001893 wait_for_completion(&cifsd_complete);
1894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 } else
1896 cFYI(1, ("No session or bad tcon"));
1897 sesInfoFree(pSesInfo);
1898 /* pSesInfo = NULL; */
1899 }
1900 }
1901 } else {
1902 atomic_inc(&tcon->useCount);
1903 cifs_sb->tcon = tcon;
1904 tcon->ses = pSesInfo;
1905
1906 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001907 CIFSSMBQFSDeviceInfo(xid, tcon);
1908 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001910 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 if(!volume_info.no_psx_acl) {
1912 if(CIFS_UNIX_POSIX_ACL_CAP &
1913 le64_to_cpu(tcon->fsUnixInfo.Capability))
1914 cFYI(1,("server negotiated posix acl support"));
1915 sb->s_flags |= MS_POSIXACL;
1916 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001917
1918 /* Try and negotiate POSIX pathnames if we can. */
1919 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1920 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French45abc6e2005-06-23 13:42:03 -05001921 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
Jeremy Allisonac670552005-06-22 17:26:35 -07001922 cFYI(1,("negotiated posix pathnames support"));
1923 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1924 } else {
1925 cFYI(1,("posix pathnames support requested but not supported"));
1926 }
1927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 }
1929 }
Steve French3e844692005-10-03 13:37:24 -07001930 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
1931 cifs_sb->wsize = min(cifs_sb->wsize,
1932 (tcon->ses->server->maxBuf -
1933 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07001934 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
1935 cifs_sb->rsize = min(cifs_sb->rsize,
1936 (tcon->ses->server->maxBuf -
1937 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 }
1939
1940 /* volume_info.password is freed above when existing session found
1941 (in which case it is not needed anymore) but when new sesion is created
1942 the password ptr is put in the new session structure (in which case the
1943 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001944 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 FreeXid(xid);
1946 return rc;
1947}
1948
1949static int
1950CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1951 char session_key[CIFS_SESSION_KEY_SIZE],
1952 const struct nls_table *nls_codepage)
1953{
1954 struct smb_hdr *smb_buffer;
1955 struct smb_hdr *smb_buffer_response;
1956 SESSION_SETUP_ANDX *pSMB;
1957 SESSION_SETUP_ANDX *pSMBr;
1958 char *bcc_ptr;
1959 char *user;
1960 char *domain;
1961 int rc = 0;
1962 int remaining_words = 0;
1963 int bytes_returned = 0;
1964 int len;
1965 __u32 capabilities;
1966 __u16 count;
1967
1968 cFYI(1, ("In sesssetup "));
1969 if(ses == NULL)
1970 return -EINVAL;
1971 user = ses->userName;
1972 domain = ses->domainName;
1973 smb_buffer = cifs_buf_get();
1974 if (smb_buffer == NULL) {
1975 return -ENOMEM;
1976 }
1977 smb_buffer_response = smb_buffer;
1978 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1979
1980 /* send SMBsessionSetup here */
1981 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1982 NULL /* no tCon exists yet */ , 13 /* wct */ );
1983
Steve French1982c342005-08-17 12:38:22 -07001984 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 pSMB->req_no_secext.AndXCommand = 0xFF;
1986 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1987 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1988
1989 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1990 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1991
1992 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1993 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1994 if (ses->capabilities & CAP_UNICODE) {
1995 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1996 capabilities |= CAP_UNICODE;
1997 }
1998 if (ses->capabilities & CAP_STATUS32) {
1999 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2000 capabilities |= CAP_STATUS32;
2001 }
2002 if (ses->capabilities & CAP_DFS) {
2003 smb_buffer->Flags2 |= SMBFLG2_DFS;
2004 capabilities |= CAP_DFS;
2005 }
2006 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2007
2008 pSMB->req_no_secext.CaseInsensitivePasswordLength =
2009 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2010
2011 pSMB->req_no_secext.CaseSensitivePasswordLength =
2012 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2013 bcc_ptr = pByteArea(smb_buffer);
2014 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
2015 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2016 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
2017 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2018
2019 if (ses->capabilities & CAP_UNICODE) {
2020 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2021 *bcc_ptr = 0;
2022 bcc_ptr++;
2023 }
2024 if(user == NULL)
2025 bytes_returned = 0; /* skill null user */
2026 else
2027 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002028 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 nls_codepage);
2030 /* convert number of 16 bit words to bytes */
2031 bcc_ptr += 2 * bytes_returned;
2032 bcc_ptr += 2; /* trailing null */
2033 if (domain == NULL)
2034 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002035 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 "CIFS_LINUX_DOM", 32, nls_codepage);
2037 else
2038 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002039 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 nls_codepage);
2041 bcc_ptr += 2 * bytes_returned;
2042 bcc_ptr += 2;
2043 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002044 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 32, nls_codepage);
2046 bcc_ptr += 2 * bytes_returned;
2047 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002048 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 32, nls_codepage);
2050 bcc_ptr += 2 * bytes_returned;
2051 bcc_ptr += 2;
2052 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002053 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 64, nls_codepage);
2055 bcc_ptr += 2 * bytes_returned;
2056 bcc_ptr += 2;
2057 } else {
2058 if(user != NULL) {
2059 strncpy(bcc_ptr, user, 200);
2060 bcc_ptr += strnlen(user, 200);
2061 }
2062 *bcc_ptr = 0;
2063 bcc_ptr++;
2064 if (domain == NULL) {
2065 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2066 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2067 } else {
2068 strncpy(bcc_ptr, domain, 64);
2069 bcc_ptr += strnlen(domain, 64);
2070 *bcc_ptr = 0;
2071 bcc_ptr++;
2072 }
2073 strcpy(bcc_ptr, "Linux version ");
2074 bcc_ptr += strlen("Linux version ");
2075 strcpy(bcc_ptr, system_utsname.release);
2076 bcc_ptr += strlen(system_utsname.release) + 1;
2077 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2078 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2079 }
2080 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2081 smb_buffer->smb_buf_length += count;
2082 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2083
2084 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2085 &bytes_returned, 1);
2086 if (rc) {
2087/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2088 } else if ((smb_buffer_response->WordCount == 3)
2089 || (smb_buffer_response->WordCount == 4)) {
2090 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2091 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2092 if (action & GUEST_LOGIN)
2093 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2094 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2095 cFYI(1, ("UID = %d ", ses->Suid));
2096 /* response can have either 3 or 4 word count - Samba sends 3 */
2097 bcc_ptr = pByteArea(smb_buffer_response);
2098 if ((pSMBr->resp.hdr.WordCount == 3)
2099 || ((pSMBr->resp.hdr.WordCount == 4)
2100 && (blob_len < pSMBr->resp.ByteCount))) {
2101 if (pSMBr->resp.hdr.WordCount == 4)
2102 bcc_ptr += blob_len;
2103
2104 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2105 if ((long) (bcc_ptr) % 2) {
2106 remaining_words =
2107 (BCC(smb_buffer_response) - 1) /2;
2108 bcc_ptr++; /* Unicode strings must be word aligned */
2109 } else {
2110 remaining_words =
2111 BCC(smb_buffer_response) / 2;
2112 }
2113 len =
2114 UniStrnlen((wchar_t *) bcc_ptr,
2115 remaining_words - 1);
2116/* We look for obvious messed up bcc or strings in response so we do not go off
2117 the end since (at least) WIN2K and Windows XP have a major bug in not null
2118 terminating last Unicode string in response */
Pekka Enberge915fc42005-09-06 15:18:35 -07002119 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002120 if(ses->serverOS == NULL)
2121 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002123 (__le16 *)bcc_ptr, len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 bcc_ptr += 2 * (len + 1);
2125 remaining_words -= len + 1;
2126 ses->serverOS[2 * len] = 0;
2127 ses->serverOS[1 + (2 * len)] = 0;
2128 if (remaining_words > 0) {
2129 len = UniStrnlen((wchar_t *)bcc_ptr,
2130 remaining_words-1);
Pekka Enberge915fc42005-09-06 15:18:35 -07002131 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002132 if(ses->serverNOS == NULL)
2133 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002135 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 bcc_ptr += 2 * (len + 1);
2137 ses->serverNOS[2 * len] = 0;
2138 ses->serverNOS[1 + (2 * len)] = 0;
2139 if(strncmp(ses->serverNOS,
2140 "NT LAN Manager 4",16) == 0) {
2141 cFYI(1,("NT4 server"));
2142 ses->flags |= CIFS_SES_NT4;
2143 }
2144 remaining_words -= len + 1;
2145 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002146 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2148 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002149 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002150 if(ses->serverDomain == NULL)
2151 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002153 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 bcc_ptr += 2 * (len + 1);
2155 ses->serverDomain[2*len] = 0;
2156 ses->serverDomain[1+(2*len)] = 0;
2157 } /* else no more room so create dummy domain string */
2158 else
Steve French433dc242005-04-28 22:41:08 -07002159 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002160 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002162 /* if these kcallocs fail not much we
2163 can do, but better to not fail the
2164 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002166 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002168 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 }
2170 } else { /* ASCII */
2171 len = strnlen(bcc_ptr, 1024);
2172 if (((long) bcc_ptr + len) - (long)
2173 pByteArea(smb_buffer_response)
2174 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07002175 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002176 if(ses->serverOS == NULL)
2177 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 strncpy(ses->serverOS,bcc_ptr, len);
2179
2180 bcc_ptr += len;
2181 bcc_ptr[0] = 0; /* null terminate the string */
2182 bcc_ptr++;
2183
2184 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002185 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002186 if(ses->serverNOS == NULL)
2187 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 strncpy(ses->serverNOS, bcc_ptr, len);
2189 bcc_ptr += len;
2190 bcc_ptr[0] = 0;
2191 bcc_ptr++;
2192
2193 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002194 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002195 if(ses->serverDomain == NULL)
2196 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 strncpy(ses->serverDomain, bcc_ptr, len);
2198 bcc_ptr += len;
2199 bcc_ptr[0] = 0;
2200 bcc_ptr++;
2201 } else
2202 cFYI(1,
2203 ("Variable field of length %d extends beyond end of smb ",
2204 len));
2205 }
2206 } else {
2207 cERROR(1,
2208 (" Security Blob Length extends beyond end of SMB"));
2209 }
2210 } else {
2211 cERROR(1,
2212 (" Invalid Word count %d: ",
2213 smb_buffer_response->WordCount));
2214 rc = -EIO;
2215 }
Steve French433dc242005-04-28 22:41:08 -07002216sesssetup_nomem: /* do not return an error on nomem for the info strings,
2217 since that could make reconnection harder, and
2218 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 if (smb_buffer)
2220 cifs_buf_release(smb_buffer);
2221
2222 return rc;
2223}
2224
2225static int
2226CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2227 char *SecurityBlob,int SecurityBlobLength,
2228 const struct nls_table *nls_codepage)
2229{
2230 struct smb_hdr *smb_buffer;
2231 struct smb_hdr *smb_buffer_response;
2232 SESSION_SETUP_ANDX *pSMB;
2233 SESSION_SETUP_ANDX *pSMBr;
2234 char *bcc_ptr;
2235 char *user;
2236 char *domain;
2237 int rc = 0;
2238 int remaining_words = 0;
2239 int bytes_returned = 0;
2240 int len;
2241 __u32 capabilities;
2242 __u16 count;
2243
2244 cFYI(1, ("In spnego sesssetup "));
2245 if(ses == NULL)
2246 return -EINVAL;
2247 user = ses->userName;
2248 domain = ses->domainName;
2249
2250 smb_buffer = cifs_buf_get();
2251 if (smb_buffer == NULL) {
2252 return -ENOMEM;
2253 }
2254 smb_buffer_response = smb_buffer;
2255 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2256
2257 /* send SMBsessionSetup here */
2258 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2259 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002260
2261 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2263 pSMB->req.AndXCommand = 0xFF;
2264 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2265 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2266
2267 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2268 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2269
2270 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2271 CAP_EXTENDED_SECURITY;
2272 if (ses->capabilities & CAP_UNICODE) {
2273 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2274 capabilities |= CAP_UNICODE;
2275 }
2276 if (ses->capabilities & CAP_STATUS32) {
2277 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2278 capabilities |= CAP_STATUS32;
2279 }
2280 if (ses->capabilities & CAP_DFS) {
2281 smb_buffer->Flags2 |= SMBFLG2_DFS;
2282 capabilities |= CAP_DFS;
2283 }
2284 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2285
2286 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2287 bcc_ptr = pByteArea(smb_buffer);
2288 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2289 bcc_ptr += SecurityBlobLength;
2290
2291 if (ses->capabilities & CAP_UNICODE) {
2292 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2293 *bcc_ptr = 0;
2294 bcc_ptr++;
2295 }
2296 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002297 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2299 bcc_ptr += 2; /* trailing null */
2300 if (domain == NULL)
2301 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002302 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 "CIFS_LINUX_DOM", 32, nls_codepage);
2304 else
2305 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002306 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 nls_codepage);
2308 bcc_ptr += 2 * bytes_returned;
2309 bcc_ptr += 2;
2310 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002311 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 32, nls_codepage);
2313 bcc_ptr += 2 * bytes_returned;
2314 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002315 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 nls_codepage);
2317 bcc_ptr += 2 * bytes_returned;
2318 bcc_ptr += 2;
2319 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002320 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 64, nls_codepage);
2322 bcc_ptr += 2 * bytes_returned;
2323 bcc_ptr += 2;
2324 } else {
2325 strncpy(bcc_ptr, user, 200);
2326 bcc_ptr += strnlen(user, 200);
2327 *bcc_ptr = 0;
2328 bcc_ptr++;
2329 if (domain == NULL) {
2330 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2331 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2332 } else {
2333 strncpy(bcc_ptr, domain, 64);
2334 bcc_ptr += strnlen(domain, 64);
2335 *bcc_ptr = 0;
2336 bcc_ptr++;
2337 }
2338 strcpy(bcc_ptr, "Linux version ");
2339 bcc_ptr += strlen("Linux version ");
2340 strcpy(bcc_ptr, system_utsname.release);
2341 bcc_ptr += strlen(system_utsname.release) + 1;
2342 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2343 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2344 }
2345 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2346 smb_buffer->smb_buf_length += count;
2347 pSMB->req.ByteCount = cpu_to_le16(count);
2348
2349 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2350 &bytes_returned, 1);
2351 if (rc) {
2352/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2353 } else if ((smb_buffer_response->WordCount == 3)
2354 || (smb_buffer_response->WordCount == 4)) {
2355 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2356 __u16 blob_len =
2357 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2358 if (action & GUEST_LOGIN)
2359 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2360 if (ses) {
2361 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2362 cFYI(1, ("UID = %d ", ses->Suid));
2363 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2364
2365 /* BB Fix below to make endian neutral !! */
2366
2367 if ((pSMBr->resp.hdr.WordCount == 3)
2368 || ((pSMBr->resp.hdr.WordCount == 4)
2369 && (blob_len <
2370 pSMBr->resp.ByteCount))) {
2371 if (pSMBr->resp.hdr.WordCount == 4) {
2372 bcc_ptr +=
2373 blob_len;
2374 cFYI(1,
2375 ("Security Blob Length %d ",
2376 blob_len));
2377 }
2378
2379 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2380 if ((long) (bcc_ptr) % 2) {
2381 remaining_words =
2382 (BCC(smb_buffer_response)
2383 - 1) / 2;
2384 bcc_ptr++; /* Unicode strings must be word aligned */
2385 } else {
2386 remaining_words =
2387 BCC
2388 (smb_buffer_response) / 2;
2389 }
2390 len =
2391 UniStrnlen((wchar_t *) bcc_ptr,
2392 remaining_words - 1);
2393/* We look for obvious messed up bcc or strings in response so we do not go off
2394 the end since (at least) WIN2K and Windows XP have a major bug in not null
2395 terminating last Unicode string in response */
2396 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002397 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002399 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 bcc_ptr, len,
2401 nls_codepage);
2402 bcc_ptr += 2 * (len + 1);
2403 remaining_words -= len + 1;
2404 ses->serverOS[2 * len] = 0;
2405 ses->serverOS[1 + (2 * len)] = 0;
2406 if (remaining_words > 0) {
2407 len = UniStrnlen((wchar_t *)bcc_ptr,
2408 remaining_words
2409 - 1);
2410 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002411 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 GFP_KERNEL);
2413 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002414 (__le16 *)bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 len,
2416 nls_codepage);
2417 bcc_ptr += 2 * (len + 1);
2418 ses->serverNOS[2 * len] = 0;
2419 ses->serverNOS[1 + (2 * len)] = 0;
2420 remaining_words -= len + 1;
2421 if (remaining_words > 0) {
2422 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2423 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Pekka Enberge915fc42005-09-06 15:18:35 -07002424 ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002426 (__le16 *)bcc_ptr,
2427 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 bcc_ptr += 2*(len+1);
2429 ses->serverDomain[2*len] = 0;
2430 ses->serverDomain[1+(2*len)] = 0;
2431 } /* else no more room so create dummy domain string */
2432 else
2433 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002434 kzalloc(2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 } else { /* no room so create dummy domain and NOS string */
Pekka Enberge915fc42005-09-06 15:18:35 -07002436 ses->serverDomain = kzalloc(2, GFP_KERNEL);
2437 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 }
2439 } else { /* ASCII */
2440
2441 len = strnlen(bcc_ptr, 1024);
2442 if (((long) bcc_ptr + len) - (long)
2443 pByteArea(smb_buffer_response)
2444 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07002445 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 strncpy(ses->serverOS, bcc_ptr, len);
2447
2448 bcc_ptr += len;
2449 bcc_ptr[0] = 0; /* null terminate the string */
2450 bcc_ptr++;
2451
2452 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002453 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 strncpy(ses->serverNOS, bcc_ptr, len);
2455 bcc_ptr += len;
2456 bcc_ptr[0] = 0;
2457 bcc_ptr++;
2458
2459 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002460 ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 strncpy(ses->serverDomain, bcc_ptr, len);
2462 bcc_ptr += len;
2463 bcc_ptr[0] = 0;
2464 bcc_ptr++;
2465 } else
2466 cFYI(1,
2467 ("Variable field of length %d extends beyond end of smb ",
2468 len));
2469 }
2470 } else {
2471 cERROR(1,
2472 (" Security Blob Length extends beyond end of SMB"));
2473 }
2474 } else {
2475 cERROR(1, ("No session structure passed in."));
2476 }
2477 } else {
2478 cERROR(1,
2479 (" Invalid Word count %d: ",
2480 smb_buffer_response->WordCount));
2481 rc = -EIO;
2482 }
2483
2484 if (smb_buffer)
2485 cifs_buf_release(smb_buffer);
2486
2487 return rc;
2488}
2489
2490static int
2491CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2492 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2493 const struct nls_table *nls_codepage)
2494{
2495 struct smb_hdr *smb_buffer;
2496 struct smb_hdr *smb_buffer_response;
2497 SESSION_SETUP_ANDX *pSMB;
2498 SESSION_SETUP_ANDX *pSMBr;
2499 char *bcc_ptr;
2500 char *domain;
2501 int rc = 0;
2502 int remaining_words = 0;
2503 int bytes_returned = 0;
2504 int len;
2505 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2506 PNEGOTIATE_MESSAGE SecurityBlob;
2507 PCHALLENGE_MESSAGE SecurityBlob2;
2508 __u32 negotiate_flags, capabilities;
2509 __u16 count;
2510
2511 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2512 if(ses == NULL)
2513 return -EINVAL;
2514 domain = ses->domainName;
2515 *pNTLMv2_flag = FALSE;
2516 smb_buffer = cifs_buf_get();
2517 if (smb_buffer == NULL) {
2518 return -ENOMEM;
2519 }
2520 smb_buffer_response = smb_buffer;
2521 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2522 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2523
2524 /* send SMBsessionSetup here */
2525 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2526 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002527
2528 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2530 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2531
2532 pSMB->req.AndXCommand = 0xFF;
2533 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2534 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2535
2536 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2537 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2538
2539 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2540 CAP_EXTENDED_SECURITY;
2541 if (ses->capabilities & CAP_UNICODE) {
2542 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2543 capabilities |= CAP_UNICODE;
2544 }
2545 if (ses->capabilities & CAP_STATUS32) {
2546 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2547 capabilities |= CAP_STATUS32;
2548 }
2549 if (ses->capabilities & CAP_DFS) {
2550 smb_buffer->Flags2 |= SMBFLG2_DFS;
2551 capabilities |= CAP_DFS;
2552 }
2553 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2554
2555 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2556 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2557 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2558 SecurityBlob->MessageType = NtLmNegotiate;
2559 negotiate_flags =
2560 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2561 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2562 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2563 if(sign_CIFS_PDUs)
2564 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2565 if(ntlmv2_support)
2566 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2567 /* setup pointers to domain name and workstation name */
2568 bcc_ptr += SecurityBlobLength;
2569
2570 SecurityBlob->WorkstationName.Buffer = 0;
2571 SecurityBlob->WorkstationName.Length = 0;
2572 SecurityBlob->WorkstationName.MaximumLength = 0;
2573
2574 if (domain == NULL) {
2575 SecurityBlob->DomainName.Buffer = 0;
2576 SecurityBlob->DomainName.Length = 0;
2577 SecurityBlob->DomainName.MaximumLength = 0;
2578 } else {
2579 __u16 len;
2580 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2581 strncpy(bcc_ptr, domain, 63);
2582 len = strnlen(domain, 64);
2583 SecurityBlob->DomainName.MaximumLength =
2584 cpu_to_le16(len);
2585 SecurityBlob->DomainName.Buffer =
2586 cpu_to_le32((long) &SecurityBlob->
2587 DomainString -
2588 (long) &SecurityBlob->Signature);
2589 bcc_ptr += len;
2590 SecurityBlobLength += len;
2591 SecurityBlob->DomainName.Length =
2592 cpu_to_le16(len);
2593 }
2594 if (ses->capabilities & CAP_UNICODE) {
2595 if ((long) bcc_ptr % 2) {
2596 *bcc_ptr = 0;
2597 bcc_ptr++;
2598 }
2599
2600 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002601 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 32, nls_codepage);
2603 bcc_ptr += 2 * bytes_returned;
2604 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002605 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 nls_codepage);
2607 bcc_ptr += 2 * bytes_returned;
2608 bcc_ptr += 2; /* null terminate Linux version */
2609 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002610 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 64, nls_codepage);
2612 bcc_ptr += 2 * bytes_returned;
2613 *(bcc_ptr + 1) = 0;
2614 *(bcc_ptr + 2) = 0;
2615 bcc_ptr += 2; /* null terminate network opsys string */
2616 *(bcc_ptr + 1) = 0;
2617 *(bcc_ptr + 2) = 0;
2618 bcc_ptr += 2; /* null domain */
2619 } else { /* ASCII */
2620 strcpy(bcc_ptr, "Linux version ");
2621 bcc_ptr += strlen("Linux version ");
2622 strcpy(bcc_ptr, system_utsname.release);
2623 bcc_ptr += strlen(system_utsname.release) + 1;
2624 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2625 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2626 bcc_ptr++; /* empty domain field */
2627 *bcc_ptr = 0;
2628 }
2629 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2630 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2631 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2632 smb_buffer->smb_buf_length += count;
2633 pSMB->req.ByteCount = cpu_to_le16(count);
2634
2635 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2636 &bytes_returned, 1);
2637
2638 if (smb_buffer_response->Status.CifsError ==
2639 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2640 rc = 0;
2641
2642 if (rc) {
2643/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2644 } else if ((smb_buffer_response->WordCount == 3)
2645 || (smb_buffer_response->WordCount == 4)) {
2646 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2647 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2648
2649 if (action & GUEST_LOGIN)
2650 cFYI(1, (" Guest login"));
2651 /* Do we want to set anything in SesInfo struct when guest login? */
2652
2653 bcc_ptr = pByteArea(smb_buffer_response);
2654 /* response can have either 3 or 4 word count - Samba sends 3 */
2655
2656 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2657 if (SecurityBlob2->MessageType != NtLmChallenge) {
2658 cFYI(1,
2659 ("Unexpected NTLMSSP message type received %d",
2660 SecurityBlob2->MessageType));
2661 } else if (ses) {
2662 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2663 cFYI(1, ("UID = %d ", ses->Suid));
2664 if ((pSMBr->resp.hdr.WordCount == 3)
2665 || ((pSMBr->resp.hdr.WordCount == 4)
2666 && (blob_len <
2667 pSMBr->resp.ByteCount))) {
2668
2669 if (pSMBr->resp.hdr.WordCount == 4) {
2670 bcc_ptr += blob_len;
2671 cFYI(1,
2672 ("Security Blob Length %d ",
2673 blob_len));
2674 }
2675
2676 cFYI(1, ("NTLMSSP Challenge rcvd "));
2677
2678 memcpy(ses->server->cryptKey,
2679 SecurityBlob2->Challenge,
2680 CIFS_CRYPTO_KEY_SIZE);
2681 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2682 *pNTLMv2_flag = TRUE;
2683
2684 if((SecurityBlob2->NegotiateFlags &
2685 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2686 || (sign_CIFS_PDUs > 1))
2687 ses->server->secMode |=
2688 SECMODE_SIGN_REQUIRED;
2689 if ((SecurityBlob2->NegotiateFlags &
2690 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2691 ses->server->secMode |=
2692 SECMODE_SIGN_ENABLED;
2693
2694 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2695 if ((long) (bcc_ptr) % 2) {
2696 remaining_words =
2697 (BCC(smb_buffer_response)
2698 - 1) / 2;
2699 bcc_ptr++; /* Unicode strings must be word aligned */
2700 } else {
2701 remaining_words =
2702 BCC
2703 (smb_buffer_response) / 2;
2704 }
2705 len =
2706 UniStrnlen((wchar_t *) bcc_ptr,
2707 remaining_words - 1);
2708/* We look for obvious messed up bcc or strings in response so we do not go off
2709 the end since (at least) WIN2K and Windows XP have a major bug in not null
2710 terminating last Unicode string in response */
2711 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002712 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002714 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 bcc_ptr, len,
2716 nls_codepage);
2717 bcc_ptr += 2 * (len + 1);
2718 remaining_words -= len + 1;
2719 ses->serverOS[2 * len] = 0;
2720 ses->serverOS[1 + (2 * len)] = 0;
2721 if (remaining_words > 0) {
2722 len = UniStrnlen((wchar_t *)
2723 bcc_ptr,
2724 remaining_words
2725 - 1);
2726 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002727 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 GFP_KERNEL);
2729 cifs_strfromUCS_le(ses->
2730 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002731 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 bcc_ptr,
2733 len,
2734 nls_codepage);
2735 bcc_ptr += 2 * (len + 1);
2736 ses->serverNOS[2 * len] = 0;
2737 ses->serverNOS[1 +
2738 (2 * len)] = 0;
2739 remaining_words -= len + 1;
2740 if (remaining_words > 0) {
2741 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2742 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2743 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002744 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 (len +
2746 1),
2747 GFP_KERNEL);
2748 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002749 (ses->serverDomain,
2750 (__le16 *)bcc_ptr,
2751 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 bcc_ptr +=
2753 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002754 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002756 ses->serverDomain
2757 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 = 0;
2759 } /* else no more room so create dummy domain string */
2760 else
2761 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002762 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 GFP_KERNEL);
2764 } else { /* no room so create dummy domain and NOS string */
2765 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002766 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002768 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 }
2770 } else { /* ASCII */
2771 len = strnlen(bcc_ptr, 1024);
2772 if (((long) bcc_ptr + len) - (long)
2773 pByteArea(smb_buffer_response)
2774 <= BCC(smb_buffer_response)) {
2775 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002776 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 GFP_KERNEL);
2778 strncpy(ses->serverOS,
2779 bcc_ptr, len);
2780
2781 bcc_ptr += len;
2782 bcc_ptr[0] = 0; /* null terminate string */
2783 bcc_ptr++;
2784
2785 len = strnlen(bcc_ptr, 1024);
2786 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002787 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 GFP_KERNEL);
2789 strncpy(ses->serverNOS, bcc_ptr, len);
2790 bcc_ptr += len;
2791 bcc_ptr[0] = 0;
2792 bcc_ptr++;
2793
2794 len = strnlen(bcc_ptr, 1024);
2795 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002796 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 GFP_KERNEL);
2798 strncpy(ses->serverDomain, bcc_ptr, len);
2799 bcc_ptr += len;
2800 bcc_ptr[0] = 0;
2801 bcc_ptr++;
2802 } else
2803 cFYI(1,
2804 ("Variable field of length %d extends beyond end of smb ",
2805 len));
2806 }
2807 } else {
2808 cERROR(1,
2809 (" Security Blob Length extends beyond end of SMB"));
2810 }
2811 } else {
2812 cERROR(1, ("No session structure passed in."));
2813 }
2814 } else {
2815 cERROR(1,
2816 (" Invalid Word count %d: ",
2817 smb_buffer_response->WordCount));
2818 rc = -EIO;
2819 }
2820
2821 if (smb_buffer)
2822 cifs_buf_release(smb_buffer);
2823
2824 return rc;
2825}
2826static int
2827CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2828 char *ntlm_session_key, int ntlmv2_flag,
2829 const struct nls_table *nls_codepage)
2830{
2831 struct smb_hdr *smb_buffer;
2832 struct smb_hdr *smb_buffer_response;
2833 SESSION_SETUP_ANDX *pSMB;
2834 SESSION_SETUP_ANDX *pSMBr;
2835 char *bcc_ptr;
2836 char *user;
2837 char *domain;
2838 int rc = 0;
2839 int remaining_words = 0;
2840 int bytes_returned = 0;
2841 int len;
2842 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2843 PAUTHENTICATE_MESSAGE SecurityBlob;
2844 __u32 negotiate_flags, capabilities;
2845 __u16 count;
2846
2847 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2848 if(ses == NULL)
2849 return -EINVAL;
2850 user = ses->userName;
2851 domain = ses->domainName;
2852 smb_buffer = cifs_buf_get();
2853 if (smb_buffer == NULL) {
2854 return -ENOMEM;
2855 }
2856 smb_buffer_response = smb_buffer;
2857 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2858 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2859
2860 /* send SMBsessionSetup here */
2861 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2862 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002863
2864 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2866 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2867 pSMB->req.AndXCommand = 0xFF;
2868 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2869 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2870
2871 pSMB->req.hdr.Uid = ses->Suid;
2872
2873 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2874 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2875
2876 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2877 CAP_EXTENDED_SECURITY;
2878 if (ses->capabilities & CAP_UNICODE) {
2879 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2880 capabilities |= CAP_UNICODE;
2881 }
2882 if (ses->capabilities & CAP_STATUS32) {
2883 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2884 capabilities |= CAP_STATUS32;
2885 }
2886 if (ses->capabilities & CAP_DFS) {
2887 smb_buffer->Flags2 |= SMBFLG2_DFS;
2888 capabilities |= CAP_DFS;
2889 }
2890 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2891
2892 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2893 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2894 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2895 SecurityBlob->MessageType = NtLmAuthenticate;
2896 bcc_ptr += SecurityBlobLength;
2897 negotiate_flags =
2898 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2899 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2900 0x80000000 | NTLMSSP_NEGOTIATE_128;
2901 if(sign_CIFS_PDUs)
2902 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2903 if(ntlmv2_flag)
2904 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2905
2906/* setup pointers to domain name and workstation name */
2907
2908 SecurityBlob->WorkstationName.Buffer = 0;
2909 SecurityBlob->WorkstationName.Length = 0;
2910 SecurityBlob->WorkstationName.MaximumLength = 0;
2911 SecurityBlob->SessionKey.Length = 0;
2912 SecurityBlob->SessionKey.MaximumLength = 0;
2913 SecurityBlob->SessionKey.Buffer = 0;
2914
2915 SecurityBlob->LmChallengeResponse.Length = 0;
2916 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2917 SecurityBlob->LmChallengeResponse.Buffer = 0;
2918
2919 SecurityBlob->NtChallengeResponse.Length =
2920 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2921 SecurityBlob->NtChallengeResponse.MaximumLength =
2922 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2923 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2924 SecurityBlob->NtChallengeResponse.Buffer =
2925 cpu_to_le32(SecurityBlobLength);
2926 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2927 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2928
2929 if (ses->capabilities & CAP_UNICODE) {
2930 if (domain == NULL) {
2931 SecurityBlob->DomainName.Buffer = 0;
2932 SecurityBlob->DomainName.Length = 0;
2933 SecurityBlob->DomainName.MaximumLength = 0;
2934 } else {
2935 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002936 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 nls_codepage);
2938 len *= 2;
2939 SecurityBlob->DomainName.MaximumLength =
2940 cpu_to_le16(len);
2941 SecurityBlob->DomainName.Buffer =
2942 cpu_to_le32(SecurityBlobLength);
2943 bcc_ptr += len;
2944 SecurityBlobLength += len;
2945 SecurityBlob->DomainName.Length =
2946 cpu_to_le16(len);
2947 }
2948 if (user == NULL) {
2949 SecurityBlob->UserName.Buffer = 0;
2950 SecurityBlob->UserName.Length = 0;
2951 SecurityBlob->UserName.MaximumLength = 0;
2952 } else {
2953 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002954 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 nls_codepage);
2956 len *= 2;
2957 SecurityBlob->UserName.MaximumLength =
2958 cpu_to_le16(len);
2959 SecurityBlob->UserName.Buffer =
2960 cpu_to_le32(SecurityBlobLength);
2961 bcc_ptr += len;
2962 SecurityBlobLength += len;
2963 SecurityBlob->UserName.Length =
2964 cpu_to_le16(len);
2965 }
2966
Steve Frenche89dc922005-11-11 15:18:19 -08002967 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 SecurityBlob->WorkstationName.Length *= 2;
2969 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2970 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2971 bcc_ptr += SecurityBlob->WorkstationName.Length;
2972 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2973 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2974
2975 if ((long) bcc_ptr % 2) {
2976 *bcc_ptr = 0;
2977 bcc_ptr++;
2978 }
2979 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002980 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 32, nls_codepage);
2982 bcc_ptr += 2 * bytes_returned;
2983 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002984 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 nls_codepage);
2986 bcc_ptr += 2 * bytes_returned;
2987 bcc_ptr += 2; /* null term version string */
2988 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002989 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 64, nls_codepage);
2991 bcc_ptr += 2 * bytes_returned;
2992 *(bcc_ptr + 1) = 0;
2993 *(bcc_ptr + 2) = 0;
2994 bcc_ptr += 2; /* null terminate network opsys string */
2995 *(bcc_ptr + 1) = 0;
2996 *(bcc_ptr + 2) = 0;
2997 bcc_ptr += 2; /* null domain */
2998 } else { /* ASCII */
2999 if (domain == NULL) {
3000 SecurityBlob->DomainName.Buffer = 0;
3001 SecurityBlob->DomainName.Length = 0;
3002 SecurityBlob->DomainName.MaximumLength = 0;
3003 } else {
3004 __u16 len;
3005 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3006 strncpy(bcc_ptr, domain, 63);
3007 len = strnlen(domain, 64);
3008 SecurityBlob->DomainName.MaximumLength =
3009 cpu_to_le16(len);
3010 SecurityBlob->DomainName.Buffer =
3011 cpu_to_le32(SecurityBlobLength);
3012 bcc_ptr += len;
3013 SecurityBlobLength += len;
3014 SecurityBlob->DomainName.Length = cpu_to_le16(len);
3015 }
3016 if (user == NULL) {
3017 SecurityBlob->UserName.Buffer = 0;
3018 SecurityBlob->UserName.Length = 0;
3019 SecurityBlob->UserName.MaximumLength = 0;
3020 } else {
3021 __u16 len;
3022 strncpy(bcc_ptr, user, 63);
3023 len = strnlen(user, 64);
3024 SecurityBlob->UserName.MaximumLength =
3025 cpu_to_le16(len);
3026 SecurityBlob->UserName.Buffer =
3027 cpu_to_le32(SecurityBlobLength);
3028 bcc_ptr += len;
3029 SecurityBlobLength += len;
3030 SecurityBlob->UserName.Length = cpu_to_le16(len);
3031 }
3032 /* BB fill in our workstation name if known BB */
3033
3034 strcpy(bcc_ptr, "Linux version ");
3035 bcc_ptr += strlen("Linux version ");
3036 strcpy(bcc_ptr, system_utsname.release);
3037 bcc_ptr += strlen(system_utsname.release) + 1;
3038 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3039 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3040 bcc_ptr++; /* null domain */
3041 *bcc_ptr = 0;
3042 }
3043 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3044 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3045 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3046 smb_buffer->smb_buf_length += count;
3047 pSMB->req.ByteCount = cpu_to_le16(count);
3048
3049 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3050 &bytes_returned, 1);
3051 if (rc) {
3052/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3053 } else if ((smb_buffer_response->WordCount == 3)
3054 || (smb_buffer_response->WordCount == 4)) {
3055 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3056 __u16 blob_len =
3057 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3058 if (action & GUEST_LOGIN)
3059 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3060/* if(SecurityBlob2->MessageType != NtLm??){
3061 cFYI("Unexpected message type on auth response is %d "));
3062 } */
3063 if (ses) {
3064 cFYI(1,
3065 ("Does UID on challenge %d match auth response UID %d ",
3066 ses->Suid, smb_buffer_response->Uid));
3067 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3068 bcc_ptr = pByteArea(smb_buffer_response);
3069 /* response can have either 3 or 4 word count - Samba sends 3 */
3070 if ((pSMBr->resp.hdr.WordCount == 3)
3071 || ((pSMBr->resp.hdr.WordCount == 4)
3072 && (blob_len <
3073 pSMBr->resp.ByteCount))) {
3074 if (pSMBr->resp.hdr.WordCount == 4) {
3075 bcc_ptr +=
3076 blob_len;
3077 cFYI(1,
3078 ("Security Blob Length %d ",
3079 blob_len));
3080 }
3081
3082 cFYI(1,
3083 ("NTLMSSP response to Authenticate "));
3084
3085 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3086 if ((long) (bcc_ptr) % 2) {
3087 remaining_words =
3088 (BCC(smb_buffer_response)
3089 - 1) / 2;
3090 bcc_ptr++; /* Unicode strings must be word aligned */
3091 } else {
3092 remaining_words = BCC(smb_buffer_response) / 2;
3093 }
3094 len =
3095 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3096/* We look for obvious messed up bcc or strings in response so we do not go off
3097 the end since (at least) WIN2K and Windows XP have a major bug in not null
3098 terminating last Unicode string in response */
3099 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003100 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003102 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 bcc_ptr, len,
3104 nls_codepage);
3105 bcc_ptr += 2 * (len + 1);
3106 remaining_words -= len + 1;
3107 ses->serverOS[2 * len] = 0;
3108 ses->serverOS[1 + (2 * len)] = 0;
3109 if (remaining_words > 0) {
3110 len = UniStrnlen((wchar_t *)
3111 bcc_ptr,
3112 remaining_words
3113 - 1);
3114 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003115 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 GFP_KERNEL);
3117 cifs_strfromUCS_le(ses->
3118 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003119 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 bcc_ptr,
3121 len,
3122 nls_codepage);
3123 bcc_ptr += 2 * (len + 1);
3124 ses->serverNOS[2 * len] = 0;
3125 ses->serverNOS[1+(2*len)] = 0;
3126 remaining_words -= len + 1;
3127 if (remaining_words > 0) {
3128 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3129 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3130 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003131 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 (len +
3133 1),
3134 GFP_KERNEL);
3135 cifs_strfromUCS_le
3136 (ses->
3137 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003138 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 bcc_ptr, len,
3140 nls_codepage);
3141 bcc_ptr +=
3142 2 * (len + 1);
3143 ses->
3144 serverDomain[2
3145 * len]
3146 = 0;
3147 ses->
3148 serverDomain[1
3149 +
3150 (2
3151 *
3152 len)]
3153 = 0;
3154 } /* else no more room so create dummy domain string */
3155 else
Pekka Enberge915fc42005-09-06 15:18:35 -07003156 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 } else { /* no room so create dummy domain and NOS string */
Pekka Enberge915fc42005-09-06 15:18:35 -07003158 ses->serverDomain = kzalloc(2, GFP_KERNEL);
3159 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 }
3161 } else { /* ASCII */
3162 len = strnlen(bcc_ptr, 1024);
3163 if (((long) bcc_ptr + len) -
3164 (long) pByteArea(smb_buffer_response)
3165 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07003166 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 strncpy(ses->serverOS,bcc_ptr, len);
3168
3169 bcc_ptr += len;
3170 bcc_ptr[0] = 0; /* null terminate the string */
3171 bcc_ptr++;
3172
3173 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07003174 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 strncpy(ses->serverNOS, bcc_ptr, len);
3176 bcc_ptr += len;
3177 bcc_ptr[0] = 0;
3178 bcc_ptr++;
3179
3180 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07003181 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 strncpy(ses->serverDomain, bcc_ptr, len);
3183 bcc_ptr += len;
3184 bcc_ptr[0] = 0;
3185 bcc_ptr++;
3186 } else
3187 cFYI(1,
3188 ("Variable field of length %d extends beyond end of smb ",
3189 len));
3190 }
3191 } else {
3192 cERROR(1,
3193 (" Security Blob Length extends beyond end of SMB"));
3194 }
3195 } else {
3196 cERROR(1, ("No session structure passed in."));
3197 }
3198 } else {
3199 cERROR(1,
3200 (" Invalid Word count %d: ",
3201 smb_buffer_response->WordCount));
3202 rc = -EIO;
3203 }
3204
3205 if (smb_buffer)
3206 cifs_buf_release(smb_buffer);
3207
3208 return rc;
3209}
3210
3211int
3212CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3213 const char *tree, struct cifsTconInfo *tcon,
3214 const struct nls_table *nls_codepage)
3215{
3216 struct smb_hdr *smb_buffer;
3217 struct smb_hdr *smb_buffer_response;
3218 TCONX_REQ *pSMB;
3219 TCONX_RSP *pSMBr;
3220 unsigned char *bcc_ptr;
3221 int rc = 0;
3222 int length;
3223 __u16 count;
3224
3225 if (ses == NULL)
3226 return -EIO;
3227
3228 smb_buffer = cifs_buf_get();
3229 if (smb_buffer == NULL) {
3230 return -ENOMEM;
3231 }
3232 smb_buffer_response = smb_buffer;
3233
3234 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3235 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003236
3237 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 smb_buffer->Uid = ses->Suid;
3239 pSMB = (TCONX_REQ *) smb_buffer;
3240 pSMBr = (TCONX_RSP *) smb_buffer_response;
3241
3242 pSMB->AndXCommand = 0xFF;
3243 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3244 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3245 bcc_ptr = &pSMB->Password[0];
3246 bcc_ptr++; /* skip password */
3247
3248 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3249 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3250
3251 if (ses->capabilities & CAP_STATUS32) {
3252 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3253 }
3254 if (ses->capabilities & CAP_DFS) {
3255 smb_buffer->Flags2 |= SMBFLG2_DFS;
3256 }
3257 if (ses->capabilities & CAP_UNICODE) {
3258 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3259 length =
Steve Frenche89dc922005-11-11 15:18:19 -08003260 cifs_strtoUCS((__le16 *) bcc_ptr, tree, 100, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3262 bcc_ptr += 2; /* skip trailing null */
3263 } else { /* ASCII */
3264
3265 strcpy(bcc_ptr, tree);
3266 bcc_ptr += strlen(tree) + 1;
3267 }
3268 strcpy(bcc_ptr, "?????");
3269 bcc_ptr += strlen("?????");
3270 bcc_ptr += 1;
3271 count = bcc_ptr - &pSMB->Password[0];
3272 pSMB->hdr.smb_buf_length += count;
3273 pSMB->ByteCount = cpu_to_le16(count);
3274
3275 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3276
3277 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3278 /* above now done in SendReceive */
3279 if ((rc == 0) && (tcon != NULL)) {
3280 tcon->tidStatus = CifsGood;
3281 tcon->tid = smb_buffer_response->Tid;
3282 bcc_ptr = pByteArea(smb_buffer_response);
3283 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3284 /* skip service field (NB: this field is always ASCII) */
3285 bcc_ptr += length + 1;
3286 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3287 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3288 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3289 if ((bcc_ptr + (2 * length)) -
3290 pByteArea(smb_buffer_response) <=
3291 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003292 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003294 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003296 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 length, nls_codepage);
3298 bcc_ptr += 2 * length;
3299 bcc_ptr[0] = 0; /* null terminate the string */
3300 bcc_ptr[1] = 0;
3301 bcc_ptr += 2;
3302 }
3303 /* else do not bother copying these informational fields */
3304 } else {
3305 length = strnlen(bcc_ptr, 1024);
3306 if ((bcc_ptr + length) -
3307 pByteArea(smb_buffer_response) <=
3308 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003309 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003311 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 strncpy(tcon->nativeFileSystem, bcc_ptr,
3313 length);
3314 }
3315 /* else do not bother copying these informational fields */
3316 }
3317 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3318 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3319 } else if ((rc == 0) && tcon == NULL) {
3320 /* all we need to save for IPC$ connection */
3321 ses->ipc_tid = smb_buffer_response->Tid;
3322 }
3323
3324 if (smb_buffer)
3325 cifs_buf_release(smb_buffer);
3326 return rc;
3327}
3328
3329int
3330cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3331{
3332 int rc = 0;
3333 int xid;
3334 struct cifsSesInfo *ses = NULL;
3335 struct task_struct *cifsd_task;
3336
3337 xid = GetXid();
3338
3339 if (cifs_sb->tcon) {
3340 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3341 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3342 if (rc == -EBUSY) {
3343 FreeXid(xid);
3344 return 0;
3345 }
3346 tconInfoFree(cifs_sb->tcon);
3347 if ((ses) && (ses->server)) {
3348 /* save off task so we do not refer to ses later */
3349 cifsd_task = ses->server->tsk;
3350 cFYI(1, ("About to do SMBLogoff "));
3351 rc = CIFSSMBLogoff(xid, ses);
3352 if (rc == -EBUSY) {
3353 FreeXid(xid);
3354 return 0;
3355 } else if (rc == -ESHUTDOWN) {
3356 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003357 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003359 wait_for_completion(&cifsd_complete);
3360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 rc = 0;
3362 } /* else - we have an smb session
3363 left on this socket do not kill cifsd */
3364 } else
3365 cFYI(1, ("No session or bad tcon"));
3366 }
3367
3368 cifs_sb->tcon = NULL;
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003369 if (ses)
3370 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 if (ses)
3372 sesInfoFree(ses);
3373
3374 FreeXid(xid);
3375 return rc; /* BB check if we should always return zero here */
3376}
3377
3378int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3379 struct nls_table * nls_info)
3380{
3381 int rc = 0;
3382 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3383 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003384 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385
3386 /* what if server changes its buffer size after dropping the session? */
3387 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3388 rc = CIFSSMBNegotiate(xid, pSesInfo);
3389 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3390 rc = CIFSSMBNegotiate(xid, pSesInfo);
3391 if(rc == -EAGAIN)
3392 rc = -EHOSTDOWN;
3393 }
3394 if(rc == 0) {
3395 spin_lock(&GlobalMid_Lock);
3396 if(pSesInfo->server->tcpStatus != CifsExiting)
3397 pSesInfo->server->tcpStatus = CifsGood;
3398 else
3399 rc = -EHOSTDOWN;
3400 spin_unlock(&GlobalMid_Lock);
3401
3402 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003403 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 }
3405 if (!rc) {
3406 pSesInfo->capabilities = pSesInfo->server->capabilities;
3407 if(linuxExtEnabled == 0)
3408 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003409 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3411 pSesInfo->server->secMode,
3412 pSesInfo->server->capabilities,
3413 pSesInfo->server->timeZone));
3414 if (extended_security
3415 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3416 && (pSesInfo->server->secType == NTLMSSP)) {
3417 cFYI(1, ("New style sesssetup "));
3418 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3419 NULL /* security blob */,
3420 0 /* blob length */,
3421 nls_info);
3422 } else if (extended_security
3423 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3424 && (pSesInfo->server->secType == RawNTLMSSP)) {
3425 cFYI(1, ("NTLMSSP sesssetup "));
3426 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3427 pSesInfo,
3428 &ntlmv2_flag,
3429 nls_info);
3430 if (!rc) {
3431 if(ntlmv2_flag) {
3432 char * v2_response;
3433 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3434 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3435 nls_info)) {
3436 rc = -ENOMEM;
3437 goto ss_err_exit;
3438 } else
3439 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3440 if(v2_response) {
3441 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003442 /* if(first_time)
3443 cifs_calculate_ntlmv2_mac_key(
3444 pSesInfo->server->mac_signing_key,
3445 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 kfree(v2_response);
3447 /* BB Put dummy sig in SessSetup PDU? */
3448 } else {
3449 rc = -ENOMEM;
3450 goto ss_err_exit;
3451 }
3452
3453 } else {
3454 SMBNTencrypt(pSesInfo->password,
3455 pSesInfo->server->cryptKey,
3456 ntlm_session_key);
3457
Steve Frenchad009ac2005-04-28 22:41:05 -07003458 if(first_time)
3459 cifs_calculate_mac_key(
3460 pSesInfo->server->mac_signing_key,
3461 ntlm_session_key,
3462 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 }
3464 /* for better security the weaker lanman hash not sent
3465 in AuthSessSetup so we no longer calculate it */
3466
3467 rc = CIFSNTLMSSPAuthSessSetup(xid,
3468 pSesInfo,
3469 ntlm_session_key,
3470 ntlmv2_flag,
3471 nls_info);
3472 }
3473 } else { /* old style NTLM 0.12 session setup */
3474 SMBNTencrypt(pSesInfo->password,
3475 pSesInfo->server->cryptKey,
3476 ntlm_session_key);
3477
Steve Frenchad009ac2005-04-28 22:41:05 -07003478 if(first_time)
3479 cifs_calculate_mac_key(
3480 pSesInfo->server->mac_signing_key,
3481 ntlm_session_key, pSesInfo->password);
3482
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 rc = CIFSSessSetup(xid, pSesInfo,
3484 ntlm_session_key, nls_info);
3485 }
3486 if (rc) {
3487 cERROR(1,("Send error in SessSetup = %d",rc));
3488 } else {
3489 cFYI(1,("CIFS Session Established successfully"));
3490 pSesInfo->status = CifsGood;
3491 }
3492 }
3493ss_err_exit:
3494 return rc;
3495}
3496