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