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