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