blob: e27e5ad8b5919870c5b2b9c020dcfe8d1627cfbe [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 }
1894 }
1895
1896 /* volume_info.password is freed above when existing session found
1897 (in which case it is not needed anymore) but when new sesion is created
1898 the password ptr is put in the new session structure (in which case the
1899 password will be freed at unmount time) */
1900 if(volume_info.UNC)
1901 kfree(volume_info.UNC);
1902 FreeXid(xid);
1903 return rc;
1904}
1905
1906static int
1907CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1908 char session_key[CIFS_SESSION_KEY_SIZE],
1909 const struct nls_table *nls_codepage)
1910{
1911 struct smb_hdr *smb_buffer;
1912 struct smb_hdr *smb_buffer_response;
1913 SESSION_SETUP_ANDX *pSMB;
1914 SESSION_SETUP_ANDX *pSMBr;
1915 char *bcc_ptr;
1916 char *user;
1917 char *domain;
1918 int rc = 0;
1919 int remaining_words = 0;
1920 int bytes_returned = 0;
1921 int len;
1922 __u32 capabilities;
1923 __u16 count;
1924
1925 cFYI(1, ("In sesssetup "));
1926 if(ses == NULL)
1927 return -EINVAL;
1928 user = ses->userName;
1929 domain = ses->domainName;
1930 smb_buffer = cifs_buf_get();
1931 if (smb_buffer == NULL) {
1932 return -ENOMEM;
1933 }
1934 smb_buffer_response = smb_buffer;
1935 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1936
1937 /* send SMBsessionSetup here */
1938 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1939 NULL /* no tCon exists yet */ , 13 /* wct */ );
1940
Steve French1982c342005-08-17 12:38:22 -07001941 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 pSMB->req_no_secext.AndXCommand = 0xFF;
1943 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1944 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1945
1946 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1947 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1948
1949 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1950 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1951 if (ses->capabilities & CAP_UNICODE) {
1952 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1953 capabilities |= CAP_UNICODE;
1954 }
1955 if (ses->capabilities & CAP_STATUS32) {
1956 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1957 capabilities |= CAP_STATUS32;
1958 }
1959 if (ses->capabilities & CAP_DFS) {
1960 smb_buffer->Flags2 |= SMBFLG2_DFS;
1961 capabilities |= CAP_DFS;
1962 }
1963 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1964
1965 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1966 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1967
1968 pSMB->req_no_secext.CaseSensitivePasswordLength =
1969 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1970 bcc_ptr = pByteArea(smb_buffer);
1971 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1972 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1973 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1974 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1975
1976 if (ses->capabilities & CAP_UNICODE) {
1977 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1978 *bcc_ptr = 0;
1979 bcc_ptr++;
1980 }
1981 if(user == NULL)
1982 bytes_returned = 0; /* skill null user */
1983 else
1984 bytes_returned =
1985 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1986 nls_codepage);
1987 /* convert number of 16 bit words to bytes */
1988 bcc_ptr += 2 * bytes_returned;
1989 bcc_ptr += 2; /* trailing null */
1990 if (domain == NULL)
1991 bytes_returned =
1992 cifs_strtoUCS((wchar_t *) bcc_ptr,
1993 "CIFS_LINUX_DOM", 32, nls_codepage);
1994 else
1995 bytes_returned =
1996 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1997 nls_codepage);
1998 bcc_ptr += 2 * bytes_returned;
1999 bcc_ptr += 2;
2000 bytes_returned =
2001 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2002 32, nls_codepage);
2003 bcc_ptr += 2 * bytes_returned;
2004 bytes_returned =
2005 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
2006 32, nls_codepage);
2007 bcc_ptr += 2 * bytes_returned;
2008 bcc_ptr += 2;
2009 bytes_returned =
2010 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2011 64, nls_codepage);
2012 bcc_ptr += 2 * bytes_returned;
2013 bcc_ptr += 2;
2014 } else {
2015 if(user != NULL) {
2016 strncpy(bcc_ptr, user, 200);
2017 bcc_ptr += strnlen(user, 200);
2018 }
2019 *bcc_ptr = 0;
2020 bcc_ptr++;
2021 if (domain == NULL) {
2022 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2023 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2024 } else {
2025 strncpy(bcc_ptr, domain, 64);
2026 bcc_ptr += strnlen(domain, 64);
2027 *bcc_ptr = 0;
2028 bcc_ptr++;
2029 }
2030 strcpy(bcc_ptr, "Linux version ");
2031 bcc_ptr += strlen("Linux version ");
2032 strcpy(bcc_ptr, system_utsname.release);
2033 bcc_ptr += strlen(system_utsname.release) + 1;
2034 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2035 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2036 }
2037 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2038 smb_buffer->smb_buf_length += count;
2039 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2040
2041 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2042 &bytes_returned, 1);
2043 if (rc) {
2044/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2045 } else if ((smb_buffer_response->WordCount == 3)
2046 || (smb_buffer_response->WordCount == 4)) {
2047 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2048 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2049 if (action & GUEST_LOGIN)
2050 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2051 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2052 cFYI(1, ("UID = %d ", ses->Suid));
2053 /* response can have either 3 or 4 word count - Samba sends 3 */
2054 bcc_ptr = pByteArea(smb_buffer_response);
2055 if ((pSMBr->resp.hdr.WordCount == 3)
2056 || ((pSMBr->resp.hdr.WordCount == 4)
2057 && (blob_len < pSMBr->resp.ByteCount))) {
2058 if (pSMBr->resp.hdr.WordCount == 4)
2059 bcc_ptr += blob_len;
2060
2061 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2062 if ((long) (bcc_ptr) % 2) {
2063 remaining_words =
2064 (BCC(smb_buffer_response) - 1) /2;
2065 bcc_ptr++; /* Unicode strings must be word aligned */
2066 } else {
2067 remaining_words =
2068 BCC(smb_buffer_response) / 2;
2069 }
2070 len =
2071 UniStrnlen((wchar_t *) bcc_ptr,
2072 remaining_words - 1);
2073/* We look for obvious messed up bcc or strings in response so we do not go off
2074 the end since (at least) WIN2K and Windows XP have a major bug in not null
2075 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07002076 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2077 if(ses->serverOS == NULL)
2078 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 cifs_strfromUCS_le(ses->serverOS,
2080 (wchar_t *)bcc_ptr, len,nls_codepage);
2081 bcc_ptr += 2 * (len + 1);
2082 remaining_words -= len + 1;
2083 ses->serverOS[2 * len] = 0;
2084 ses->serverOS[1 + (2 * len)] = 0;
2085 if (remaining_words > 0) {
2086 len = UniStrnlen((wchar_t *)bcc_ptr,
2087 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07002088 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2089 if(ses->serverNOS == NULL)
2090 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 cifs_strfromUCS_le(ses->serverNOS,
2092 (wchar_t *)bcc_ptr,len,nls_codepage);
2093 bcc_ptr += 2 * (len + 1);
2094 ses->serverNOS[2 * len] = 0;
2095 ses->serverNOS[1 + (2 * len)] = 0;
2096 if(strncmp(ses->serverNOS,
2097 "NT LAN Manager 4",16) == 0) {
2098 cFYI(1,("NT4 server"));
2099 ses->flags |= CIFS_SES_NT4;
2100 }
2101 remaining_words -= len + 1;
2102 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002103 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2105 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002106 kcalloc(1, 2*(len+1),GFP_KERNEL);
2107 if(ses->serverDomain == NULL)
2108 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 cifs_strfromUCS_le(ses->serverDomain,
2110 (wchar_t *)bcc_ptr,len,nls_codepage);
2111 bcc_ptr += 2 * (len + 1);
2112 ses->serverDomain[2*len] = 0;
2113 ses->serverDomain[1+(2*len)] = 0;
2114 } /* else no more room so create dummy domain string */
2115 else
Steve French433dc242005-04-28 22:41:08 -07002116 ses->serverDomain =
2117 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002119 /* if these kcallocs fail not much we
2120 can do, but better to not fail the
2121 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002123 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002125 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 }
2127 } else { /* ASCII */
2128 len = strnlen(bcc_ptr, 1024);
2129 if (((long) bcc_ptr + len) - (long)
2130 pByteArea(smb_buffer_response)
2131 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002132 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2133 if(ses->serverOS == NULL)
2134 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 strncpy(ses->serverOS,bcc_ptr, len);
2136
2137 bcc_ptr += len;
2138 bcc_ptr[0] = 0; /* null terminate the string */
2139 bcc_ptr++;
2140
2141 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002142 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2143 if(ses->serverNOS == NULL)
2144 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 strncpy(ses->serverNOS, bcc_ptr, len);
2146 bcc_ptr += len;
2147 bcc_ptr[0] = 0;
2148 bcc_ptr++;
2149
2150 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002151 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2152 if(ses->serverDomain == NULL)
2153 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 strncpy(ses->serverDomain, bcc_ptr, len);
2155 bcc_ptr += len;
2156 bcc_ptr[0] = 0;
2157 bcc_ptr++;
2158 } else
2159 cFYI(1,
2160 ("Variable field of length %d extends beyond end of smb ",
2161 len));
2162 }
2163 } else {
2164 cERROR(1,
2165 (" Security Blob Length extends beyond end of SMB"));
2166 }
2167 } else {
2168 cERROR(1,
2169 (" Invalid Word count %d: ",
2170 smb_buffer_response->WordCount));
2171 rc = -EIO;
2172 }
Steve French433dc242005-04-28 22:41:08 -07002173sesssetup_nomem: /* do not return an error on nomem for the info strings,
2174 since that could make reconnection harder, and
2175 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 if (smb_buffer)
2177 cifs_buf_release(smb_buffer);
2178
2179 return rc;
2180}
2181
2182static int
2183CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2184 char *SecurityBlob,int SecurityBlobLength,
2185 const struct nls_table *nls_codepage)
2186{
2187 struct smb_hdr *smb_buffer;
2188 struct smb_hdr *smb_buffer_response;
2189 SESSION_SETUP_ANDX *pSMB;
2190 SESSION_SETUP_ANDX *pSMBr;
2191 char *bcc_ptr;
2192 char *user;
2193 char *domain;
2194 int rc = 0;
2195 int remaining_words = 0;
2196 int bytes_returned = 0;
2197 int len;
2198 __u32 capabilities;
2199 __u16 count;
2200
2201 cFYI(1, ("In spnego sesssetup "));
2202 if(ses == NULL)
2203 return -EINVAL;
2204 user = ses->userName;
2205 domain = ses->domainName;
2206
2207 smb_buffer = cifs_buf_get();
2208 if (smb_buffer == NULL) {
2209 return -ENOMEM;
2210 }
2211 smb_buffer_response = smb_buffer;
2212 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2213
2214 /* send SMBsessionSetup here */
2215 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2216 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002217
2218 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2220 pSMB->req.AndXCommand = 0xFF;
2221 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2222 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2223
2224 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2225 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2226
2227 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2228 CAP_EXTENDED_SECURITY;
2229 if (ses->capabilities & CAP_UNICODE) {
2230 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2231 capabilities |= CAP_UNICODE;
2232 }
2233 if (ses->capabilities & CAP_STATUS32) {
2234 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2235 capabilities |= CAP_STATUS32;
2236 }
2237 if (ses->capabilities & CAP_DFS) {
2238 smb_buffer->Flags2 |= SMBFLG2_DFS;
2239 capabilities |= CAP_DFS;
2240 }
2241 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2242
2243 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2244 bcc_ptr = pByteArea(smb_buffer);
2245 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2246 bcc_ptr += SecurityBlobLength;
2247
2248 if (ses->capabilities & CAP_UNICODE) {
2249 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2250 *bcc_ptr = 0;
2251 bcc_ptr++;
2252 }
2253 bytes_returned =
2254 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2255 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2256 bcc_ptr += 2; /* trailing null */
2257 if (domain == NULL)
2258 bytes_returned =
2259 cifs_strtoUCS((wchar_t *) bcc_ptr,
2260 "CIFS_LINUX_DOM", 32, nls_codepage);
2261 else
2262 bytes_returned =
2263 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2264 nls_codepage);
2265 bcc_ptr += 2 * bytes_returned;
2266 bcc_ptr += 2;
2267 bytes_returned =
2268 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2269 32, nls_codepage);
2270 bcc_ptr += 2 * bytes_returned;
2271 bytes_returned =
2272 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2273 nls_codepage);
2274 bcc_ptr += 2 * bytes_returned;
2275 bcc_ptr += 2;
2276 bytes_returned =
2277 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2278 64, nls_codepage);
2279 bcc_ptr += 2 * bytes_returned;
2280 bcc_ptr += 2;
2281 } else {
2282 strncpy(bcc_ptr, user, 200);
2283 bcc_ptr += strnlen(user, 200);
2284 *bcc_ptr = 0;
2285 bcc_ptr++;
2286 if (domain == NULL) {
2287 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2288 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2289 } else {
2290 strncpy(bcc_ptr, domain, 64);
2291 bcc_ptr += strnlen(domain, 64);
2292 *bcc_ptr = 0;
2293 bcc_ptr++;
2294 }
2295 strcpy(bcc_ptr, "Linux version ");
2296 bcc_ptr += strlen("Linux version ");
2297 strcpy(bcc_ptr, system_utsname.release);
2298 bcc_ptr += strlen(system_utsname.release) + 1;
2299 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2300 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2301 }
2302 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2303 smb_buffer->smb_buf_length += count;
2304 pSMB->req.ByteCount = cpu_to_le16(count);
2305
2306 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2307 &bytes_returned, 1);
2308 if (rc) {
2309/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2310 } else if ((smb_buffer_response->WordCount == 3)
2311 || (smb_buffer_response->WordCount == 4)) {
2312 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2313 __u16 blob_len =
2314 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2315 if (action & GUEST_LOGIN)
2316 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2317 if (ses) {
2318 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2319 cFYI(1, ("UID = %d ", ses->Suid));
2320 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2321
2322 /* BB Fix below to make endian neutral !! */
2323
2324 if ((pSMBr->resp.hdr.WordCount == 3)
2325 || ((pSMBr->resp.hdr.WordCount == 4)
2326 && (blob_len <
2327 pSMBr->resp.ByteCount))) {
2328 if (pSMBr->resp.hdr.WordCount == 4) {
2329 bcc_ptr +=
2330 blob_len;
2331 cFYI(1,
2332 ("Security Blob Length %d ",
2333 blob_len));
2334 }
2335
2336 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2337 if ((long) (bcc_ptr) % 2) {
2338 remaining_words =
2339 (BCC(smb_buffer_response)
2340 - 1) / 2;
2341 bcc_ptr++; /* Unicode strings must be word aligned */
2342 } else {
2343 remaining_words =
2344 BCC
2345 (smb_buffer_response) / 2;
2346 }
2347 len =
2348 UniStrnlen((wchar_t *) bcc_ptr,
2349 remaining_words - 1);
2350/* We look for obvious messed up bcc or strings in response so we do not go off
2351 the end since (at least) WIN2K and Windows XP have a major bug in not null
2352 terminating last Unicode string in response */
2353 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002354 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 cifs_strfromUCS_le(ses->serverOS,
2356 (wchar_t *)
2357 bcc_ptr, len,
2358 nls_codepage);
2359 bcc_ptr += 2 * (len + 1);
2360 remaining_words -= len + 1;
2361 ses->serverOS[2 * len] = 0;
2362 ses->serverOS[1 + (2 * len)] = 0;
2363 if (remaining_words > 0) {
2364 len = UniStrnlen((wchar_t *)bcc_ptr,
2365 remaining_words
2366 - 1);
2367 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002368 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 GFP_KERNEL);
2370 cifs_strfromUCS_le(ses->serverNOS,
2371 (wchar_t *)bcc_ptr,
2372 len,
2373 nls_codepage);
2374 bcc_ptr += 2 * (len + 1);
2375 ses->serverNOS[2 * len] = 0;
2376 ses->serverNOS[1 + (2 * len)] = 0;
2377 remaining_words -= len + 1;
2378 if (remaining_words > 0) {
2379 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2380 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002381 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 cifs_strfromUCS_le(ses->serverDomain,
2383 (wchar_t *)bcc_ptr,
2384 len,
2385 nls_codepage);
2386 bcc_ptr += 2*(len+1);
2387 ses->serverDomain[2*len] = 0;
2388 ses->serverDomain[1+(2*len)] = 0;
2389 } /* else no more room so create dummy domain string */
2390 else
2391 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002392 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002394 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2395 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 }
2397 } else { /* ASCII */
2398
2399 len = strnlen(bcc_ptr, 1024);
2400 if (((long) bcc_ptr + len) - (long)
2401 pByteArea(smb_buffer_response)
2402 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002403 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 strncpy(ses->serverOS, bcc_ptr, len);
2405
2406 bcc_ptr += len;
2407 bcc_ptr[0] = 0; /* null terminate the string */
2408 bcc_ptr++;
2409
2410 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002411 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 strncpy(ses->serverNOS, bcc_ptr, len);
2413 bcc_ptr += len;
2414 bcc_ptr[0] = 0;
2415 bcc_ptr++;
2416
2417 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002418 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 strncpy(ses->serverDomain, bcc_ptr, len);
2420 bcc_ptr += len;
2421 bcc_ptr[0] = 0;
2422 bcc_ptr++;
2423 } else
2424 cFYI(1,
2425 ("Variable field of length %d extends beyond end of smb ",
2426 len));
2427 }
2428 } else {
2429 cERROR(1,
2430 (" Security Blob Length extends beyond end of SMB"));
2431 }
2432 } else {
2433 cERROR(1, ("No session structure passed in."));
2434 }
2435 } else {
2436 cERROR(1,
2437 (" Invalid Word count %d: ",
2438 smb_buffer_response->WordCount));
2439 rc = -EIO;
2440 }
2441
2442 if (smb_buffer)
2443 cifs_buf_release(smb_buffer);
2444
2445 return rc;
2446}
2447
2448static int
2449CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2450 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2451 const struct nls_table *nls_codepage)
2452{
2453 struct smb_hdr *smb_buffer;
2454 struct smb_hdr *smb_buffer_response;
2455 SESSION_SETUP_ANDX *pSMB;
2456 SESSION_SETUP_ANDX *pSMBr;
2457 char *bcc_ptr;
2458 char *domain;
2459 int rc = 0;
2460 int remaining_words = 0;
2461 int bytes_returned = 0;
2462 int len;
2463 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2464 PNEGOTIATE_MESSAGE SecurityBlob;
2465 PCHALLENGE_MESSAGE SecurityBlob2;
2466 __u32 negotiate_flags, capabilities;
2467 __u16 count;
2468
2469 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2470 if(ses == NULL)
2471 return -EINVAL;
2472 domain = ses->domainName;
2473 *pNTLMv2_flag = FALSE;
2474 smb_buffer = cifs_buf_get();
2475 if (smb_buffer == NULL) {
2476 return -ENOMEM;
2477 }
2478 smb_buffer_response = smb_buffer;
2479 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2480 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2481
2482 /* send SMBsessionSetup here */
2483 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2484 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002485
2486 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2488 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2489
2490 pSMB->req.AndXCommand = 0xFF;
2491 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2492 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2493
2494 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2495 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2496
2497 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2498 CAP_EXTENDED_SECURITY;
2499 if (ses->capabilities & CAP_UNICODE) {
2500 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2501 capabilities |= CAP_UNICODE;
2502 }
2503 if (ses->capabilities & CAP_STATUS32) {
2504 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2505 capabilities |= CAP_STATUS32;
2506 }
2507 if (ses->capabilities & CAP_DFS) {
2508 smb_buffer->Flags2 |= SMBFLG2_DFS;
2509 capabilities |= CAP_DFS;
2510 }
2511 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2512
2513 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2514 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2515 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2516 SecurityBlob->MessageType = NtLmNegotiate;
2517 negotiate_flags =
2518 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2519 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2520 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2521 if(sign_CIFS_PDUs)
2522 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2523 if(ntlmv2_support)
2524 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2525 /* setup pointers to domain name and workstation name */
2526 bcc_ptr += SecurityBlobLength;
2527
2528 SecurityBlob->WorkstationName.Buffer = 0;
2529 SecurityBlob->WorkstationName.Length = 0;
2530 SecurityBlob->WorkstationName.MaximumLength = 0;
2531
2532 if (domain == NULL) {
2533 SecurityBlob->DomainName.Buffer = 0;
2534 SecurityBlob->DomainName.Length = 0;
2535 SecurityBlob->DomainName.MaximumLength = 0;
2536 } else {
2537 __u16 len;
2538 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2539 strncpy(bcc_ptr, domain, 63);
2540 len = strnlen(domain, 64);
2541 SecurityBlob->DomainName.MaximumLength =
2542 cpu_to_le16(len);
2543 SecurityBlob->DomainName.Buffer =
2544 cpu_to_le32((long) &SecurityBlob->
2545 DomainString -
2546 (long) &SecurityBlob->Signature);
2547 bcc_ptr += len;
2548 SecurityBlobLength += len;
2549 SecurityBlob->DomainName.Length =
2550 cpu_to_le16(len);
2551 }
2552 if (ses->capabilities & CAP_UNICODE) {
2553 if ((long) bcc_ptr % 2) {
2554 *bcc_ptr = 0;
2555 bcc_ptr++;
2556 }
2557
2558 bytes_returned =
2559 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2560 32, nls_codepage);
2561 bcc_ptr += 2 * bytes_returned;
2562 bytes_returned =
2563 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2564 nls_codepage);
2565 bcc_ptr += 2 * bytes_returned;
2566 bcc_ptr += 2; /* null terminate Linux version */
2567 bytes_returned =
2568 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2569 64, nls_codepage);
2570 bcc_ptr += 2 * bytes_returned;
2571 *(bcc_ptr + 1) = 0;
2572 *(bcc_ptr + 2) = 0;
2573 bcc_ptr += 2; /* null terminate network opsys string */
2574 *(bcc_ptr + 1) = 0;
2575 *(bcc_ptr + 2) = 0;
2576 bcc_ptr += 2; /* null domain */
2577 } else { /* ASCII */
2578 strcpy(bcc_ptr, "Linux version ");
2579 bcc_ptr += strlen("Linux version ");
2580 strcpy(bcc_ptr, system_utsname.release);
2581 bcc_ptr += strlen(system_utsname.release) + 1;
2582 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2583 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2584 bcc_ptr++; /* empty domain field */
2585 *bcc_ptr = 0;
2586 }
2587 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2588 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2589 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2590 smb_buffer->smb_buf_length += count;
2591 pSMB->req.ByteCount = cpu_to_le16(count);
2592
2593 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2594 &bytes_returned, 1);
2595
2596 if (smb_buffer_response->Status.CifsError ==
2597 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2598 rc = 0;
2599
2600 if (rc) {
2601/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2602 } else if ((smb_buffer_response->WordCount == 3)
2603 || (smb_buffer_response->WordCount == 4)) {
2604 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2605 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2606
2607 if (action & GUEST_LOGIN)
2608 cFYI(1, (" Guest login"));
2609 /* Do we want to set anything in SesInfo struct when guest login? */
2610
2611 bcc_ptr = pByteArea(smb_buffer_response);
2612 /* response can have either 3 or 4 word count - Samba sends 3 */
2613
2614 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2615 if (SecurityBlob2->MessageType != NtLmChallenge) {
2616 cFYI(1,
2617 ("Unexpected NTLMSSP message type received %d",
2618 SecurityBlob2->MessageType));
2619 } else if (ses) {
2620 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2621 cFYI(1, ("UID = %d ", ses->Suid));
2622 if ((pSMBr->resp.hdr.WordCount == 3)
2623 || ((pSMBr->resp.hdr.WordCount == 4)
2624 && (blob_len <
2625 pSMBr->resp.ByteCount))) {
2626
2627 if (pSMBr->resp.hdr.WordCount == 4) {
2628 bcc_ptr += blob_len;
2629 cFYI(1,
2630 ("Security Blob Length %d ",
2631 blob_len));
2632 }
2633
2634 cFYI(1, ("NTLMSSP Challenge rcvd "));
2635
2636 memcpy(ses->server->cryptKey,
2637 SecurityBlob2->Challenge,
2638 CIFS_CRYPTO_KEY_SIZE);
2639 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2640 *pNTLMv2_flag = TRUE;
2641
2642 if((SecurityBlob2->NegotiateFlags &
2643 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2644 || (sign_CIFS_PDUs > 1))
2645 ses->server->secMode |=
2646 SECMODE_SIGN_REQUIRED;
2647 if ((SecurityBlob2->NegotiateFlags &
2648 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2649 ses->server->secMode |=
2650 SECMODE_SIGN_ENABLED;
2651
2652 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2653 if ((long) (bcc_ptr) % 2) {
2654 remaining_words =
2655 (BCC(smb_buffer_response)
2656 - 1) / 2;
2657 bcc_ptr++; /* Unicode strings must be word aligned */
2658 } else {
2659 remaining_words =
2660 BCC
2661 (smb_buffer_response) / 2;
2662 }
2663 len =
2664 UniStrnlen((wchar_t *) bcc_ptr,
2665 remaining_words - 1);
2666/* We look for obvious messed up bcc or strings in response so we do not go off
2667 the end since (at least) WIN2K and Windows XP have a major bug in not null
2668 terminating last Unicode string in response */
2669 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002670 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 cifs_strfromUCS_le(ses->serverOS,
2672 (wchar_t *)
2673 bcc_ptr, len,
2674 nls_codepage);
2675 bcc_ptr += 2 * (len + 1);
2676 remaining_words -= len + 1;
2677 ses->serverOS[2 * len] = 0;
2678 ses->serverOS[1 + (2 * len)] = 0;
2679 if (remaining_words > 0) {
2680 len = UniStrnlen((wchar_t *)
2681 bcc_ptr,
2682 remaining_words
2683 - 1);
2684 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002685 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 GFP_KERNEL);
2687 cifs_strfromUCS_le(ses->
2688 serverNOS,
2689 (wchar_t *)
2690 bcc_ptr,
2691 len,
2692 nls_codepage);
2693 bcc_ptr += 2 * (len + 1);
2694 ses->serverNOS[2 * len] = 0;
2695 ses->serverNOS[1 +
2696 (2 * len)] = 0;
2697 remaining_words -= len + 1;
2698 if (remaining_words > 0) {
2699 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2700 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2701 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002702 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 (len +
2704 1),
2705 GFP_KERNEL);
2706 cifs_strfromUCS_le
2707 (ses->
2708 serverDomain,
2709 (wchar_t *)
2710 bcc_ptr, len,
2711 nls_codepage);
2712 bcc_ptr +=
2713 2 * (len + 1);
2714 ses->
2715 serverDomain[2
2716 * len]
2717 = 0;
2718 ses->
2719 serverDomain[1
2720 +
2721 (2
2722 *
2723 len)]
2724 = 0;
2725 } /* else no more room so create dummy domain string */
2726 else
2727 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002728 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 GFP_KERNEL);
2730 } else { /* no room so create dummy domain and NOS string */
2731 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002732 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002734 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 }
2736 } else { /* ASCII */
2737 len = strnlen(bcc_ptr, 1024);
2738 if (((long) bcc_ptr + len) - (long)
2739 pByteArea(smb_buffer_response)
2740 <= BCC(smb_buffer_response)) {
2741 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002742 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 GFP_KERNEL);
2744 strncpy(ses->serverOS,
2745 bcc_ptr, len);
2746
2747 bcc_ptr += len;
2748 bcc_ptr[0] = 0; /* null terminate string */
2749 bcc_ptr++;
2750
2751 len = strnlen(bcc_ptr, 1024);
2752 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002753 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 GFP_KERNEL);
2755 strncpy(ses->serverNOS, bcc_ptr, len);
2756 bcc_ptr += len;
2757 bcc_ptr[0] = 0;
2758 bcc_ptr++;
2759
2760 len = strnlen(bcc_ptr, 1024);
2761 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002762 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 GFP_KERNEL);
2764 strncpy(ses->serverDomain, bcc_ptr, len);
2765 bcc_ptr += len;
2766 bcc_ptr[0] = 0;
2767 bcc_ptr++;
2768 } else
2769 cFYI(1,
2770 ("Variable field of length %d extends beyond end of smb ",
2771 len));
2772 }
2773 } else {
2774 cERROR(1,
2775 (" Security Blob Length extends beyond end of SMB"));
2776 }
2777 } else {
2778 cERROR(1, ("No session structure passed in."));
2779 }
2780 } else {
2781 cERROR(1,
2782 (" Invalid Word count %d: ",
2783 smb_buffer_response->WordCount));
2784 rc = -EIO;
2785 }
2786
2787 if (smb_buffer)
2788 cifs_buf_release(smb_buffer);
2789
2790 return rc;
2791}
2792static int
2793CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2794 char *ntlm_session_key, int ntlmv2_flag,
2795 const struct nls_table *nls_codepage)
2796{
2797 struct smb_hdr *smb_buffer;
2798 struct smb_hdr *smb_buffer_response;
2799 SESSION_SETUP_ANDX *pSMB;
2800 SESSION_SETUP_ANDX *pSMBr;
2801 char *bcc_ptr;
2802 char *user;
2803 char *domain;
2804 int rc = 0;
2805 int remaining_words = 0;
2806 int bytes_returned = 0;
2807 int len;
2808 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2809 PAUTHENTICATE_MESSAGE SecurityBlob;
2810 __u32 negotiate_flags, capabilities;
2811 __u16 count;
2812
2813 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2814 if(ses == NULL)
2815 return -EINVAL;
2816 user = ses->userName;
2817 domain = ses->domainName;
2818 smb_buffer = cifs_buf_get();
2819 if (smb_buffer == NULL) {
2820 return -ENOMEM;
2821 }
2822 smb_buffer_response = smb_buffer;
2823 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2824 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2825
2826 /* send SMBsessionSetup here */
2827 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2828 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002829
2830 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2832 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2833 pSMB->req.AndXCommand = 0xFF;
2834 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2835 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2836
2837 pSMB->req.hdr.Uid = ses->Suid;
2838
2839 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2840 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2841
2842 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2843 CAP_EXTENDED_SECURITY;
2844 if (ses->capabilities & CAP_UNICODE) {
2845 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2846 capabilities |= CAP_UNICODE;
2847 }
2848 if (ses->capabilities & CAP_STATUS32) {
2849 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2850 capabilities |= CAP_STATUS32;
2851 }
2852 if (ses->capabilities & CAP_DFS) {
2853 smb_buffer->Flags2 |= SMBFLG2_DFS;
2854 capabilities |= CAP_DFS;
2855 }
2856 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2857
2858 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2859 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2860 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2861 SecurityBlob->MessageType = NtLmAuthenticate;
2862 bcc_ptr += SecurityBlobLength;
2863 negotiate_flags =
2864 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2865 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2866 0x80000000 | NTLMSSP_NEGOTIATE_128;
2867 if(sign_CIFS_PDUs)
2868 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2869 if(ntlmv2_flag)
2870 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2871
2872/* setup pointers to domain name and workstation name */
2873
2874 SecurityBlob->WorkstationName.Buffer = 0;
2875 SecurityBlob->WorkstationName.Length = 0;
2876 SecurityBlob->WorkstationName.MaximumLength = 0;
2877 SecurityBlob->SessionKey.Length = 0;
2878 SecurityBlob->SessionKey.MaximumLength = 0;
2879 SecurityBlob->SessionKey.Buffer = 0;
2880
2881 SecurityBlob->LmChallengeResponse.Length = 0;
2882 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2883 SecurityBlob->LmChallengeResponse.Buffer = 0;
2884
2885 SecurityBlob->NtChallengeResponse.Length =
2886 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2887 SecurityBlob->NtChallengeResponse.MaximumLength =
2888 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2889 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2890 SecurityBlob->NtChallengeResponse.Buffer =
2891 cpu_to_le32(SecurityBlobLength);
2892 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2893 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2894
2895 if (ses->capabilities & CAP_UNICODE) {
2896 if (domain == NULL) {
2897 SecurityBlob->DomainName.Buffer = 0;
2898 SecurityBlob->DomainName.Length = 0;
2899 SecurityBlob->DomainName.MaximumLength = 0;
2900 } else {
2901 __u16 len =
2902 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2903 nls_codepage);
2904 len *= 2;
2905 SecurityBlob->DomainName.MaximumLength =
2906 cpu_to_le16(len);
2907 SecurityBlob->DomainName.Buffer =
2908 cpu_to_le32(SecurityBlobLength);
2909 bcc_ptr += len;
2910 SecurityBlobLength += len;
2911 SecurityBlob->DomainName.Length =
2912 cpu_to_le16(len);
2913 }
2914 if (user == NULL) {
2915 SecurityBlob->UserName.Buffer = 0;
2916 SecurityBlob->UserName.Length = 0;
2917 SecurityBlob->UserName.MaximumLength = 0;
2918 } else {
2919 __u16 len =
2920 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2921 nls_codepage);
2922 len *= 2;
2923 SecurityBlob->UserName.MaximumLength =
2924 cpu_to_le16(len);
2925 SecurityBlob->UserName.Buffer =
2926 cpu_to_le32(SecurityBlobLength);
2927 bcc_ptr += len;
2928 SecurityBlobLength += len;
2929 SecurityBlob->UserName.Length =
2930 cpu_to_le16(len);
2931 }
2932
2933 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2934 SecurityBlob->WorkstationName.Length *= 2;
2935 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2936 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2937 bcc_ptr += SecurityBlob->WorkstationName.Length;
2938 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2939 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2940
2941 if ((long) bcc_ptr % 2) {
2942 *bcc_ptr = 0;
2943 bcc_ptr++;
2944 }
2945 bytes_returned =
2946 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2947 32, nls_codepage);
2948 bcc_ptr += 2 * bytes_returned;
2949 bytes_returned =
2950 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2951 nls_codepage);
2952 bcc_ptr += 2 * bytes_returned;
2953 bcc_ptr += 2; /* null term version string */
2954 bytes_returned =
2955 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2956 64, nls_codepage);
2957 bcc_ptr += 2 * bytes_returned;
2958 *(bcc_ptr + 1) = 0;
2959 *(bcc_ptr + 2) = 0;
2960 bcc_ptr += 2; /* null terminate network opsys string */
2961 *(bcc_ptr + 1) = 0;
2962 *(bcc_ptr + 2) = 0;
2963 bcc_ptr += 2; /* null domain */
2964 } else { /* ASCII */
2965 if (domain == NULL) {
2966 SecurityBlob->DomainName.Buffer = 0;
2967 SecurityBlob->DomainName.Length = 0;
2968 SecurityBlob->DomainName.MaximumLength = 0;
2969 } else {
2970 __u16 len;
2971 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2972 strncpy(bcc_ptr, domain, 63);
2973 len = strnlen(domain, 64);
2974 SecurityBlob->DomainName.MaximumLength =
2975 cpu_to_le16(len);
2976 SecurityBlob->DomainName.Buffer =
2977 cpu_to_le32(SecurityBlobLength);
2978 bcc_ptr += len;
2979 SecurityBlobLength += len;
2980 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2981 }
2982 if (user == NULL) {
2983 SecurityBlob->UserName.Buffer = 0;
2984 SecurityBlob->UserName.Length = 0;
2985 SecurityBlob->UserName.MaximumLength = 0;
2986 } else {
2987 __u16 len;
2988 strncpy(bcc_ptr, user, 63);
2989 len = strnlen(user, 64);
2990 SecurityBlob->UserName.MaximumLength =
2991 cpu_to_le16(len);
2992 SecurityBlob->UserName.Buffer =
2993 cpu_to_le32(SecurityBlobLength);
2994 bcc_ptr += len;
2995 SecurityBlobLength += len;
2996 SecurityBlob->UserName.Length = cpu_to_le16(len);
2997 }
2998 /* BB fill in our workstation name if known BB */
2999
3000 strcpy(bcc_ptr, "Linux version ");
3001 bcc_ptr += strlen("Linux version ");
3002 strcpy(bcc_ptr, system_utsname.release);
3003 bcc_ptr += strlen(system_utsname.release) + 1;
3004 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3005 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3006 bcc_ptr++; /* null domain */
3007 *bcc_ptr = 0;
3008 }
3009 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3010 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3011 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3012 smb_buffer->smb_buf_length += count;
3013 pSMB->req.ByteCount = cpu_to_le16(count);
3014
3015 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3016 &bytes_returned, 1);
3017 if (rc) {
3018/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3019 } else if ((smb_buffer_response->WordCount == 3)
3020 || (smb_buffer_response->WordCount == 4)) {
3021 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3022 __u16 blob_len =
3023 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3024 if (action & GUEST_LOGIN)
3025 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3026/* if(SecurityBlob2->MessageType != NtLm??){
3027 cFYI("Unexpected message type on auth response is %d "));
3028 } */
3029 if (ses) {
3030 cFYI(1,
3031 ("Does UID on challenge %d match auth response UID %d ",
3032 ses->Suid, smb_buffer_response->Uid));
3033 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3034 bcc_ptr = pByteArea(smb_buffer_response);
3035 /* response can have either 3 or 4 word count - Samba sends 3 */
3036 if ((pSMBr->resp.hdr.WordCount == 3)
3037 || ((pSMBr->resp.hdr.WordCount == 4)
3038 && (blob_len <
3039 pSMBr->resp.ByteCount))) {
3040 if (pSMBr->resp.hdr.WordCount == 4) {
3041 bcc_ptr +=
3042 blob_len;
3043 cFYI(1,
3044 ("Security Blob Length %d ",
3045 blob_len));
3046 }
3047
3048 cFYI(1,
3049 ("NTLMSSP response to Authenticate "));
3050
3051 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3052 if ((long) (bcc_ptr) % 2) {
3053 remaining_words =
3054 (BCC(smb_buffer_response)
3055 - 1) / 2;
3056 bcc_ptr++; /* Unicode strings must be word aligned */
3057 } else {
3058 remaining_words = BCC(smb_buffer_response) / 2;
3059 }
3060 len =
3061 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3062/* We look for obvious messed up bcc or strings in response so we do not go off
3063 the end since (at least) WIN2K and Windows XP have a major bug in not null
3064 terminating last Unicode string in response */
3065 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07003066 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 cifs_strfromUCS_le(ses->serverOS,
3068 (wchar_t *)
3069 bcc_ptr, len,
3070 nls_codepage);
3071 bcc_ptr += 2 * (len + 1);
3072 remaining_words -= len + 1;
3073 ses->serverOS[2 * len] = 0;
3074 ses->serverOS[1 + (2 * len)] = 0;
3075 if (remaining_words > 0) {
3076 len = UniStrnlen((wchar_t *)
3077 bcc_ptr,
3078 remaining_words
3079 - 1);
3080 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07003081 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 GFP_KERNEL);
3083 cifs_strfromUCS_le(ses->
3084 serverNOS,
3085 (wchar_t *)
3086 bcc_ptr,
3087 len,
3088 nls_codepage);
3089 bcc_ptr += 2 * (len + 1);
3090 ses->serverNOS[2 * len] = 0;
3091 ses->serverNOS[1+(2*len)] = 0;
3092 remaining_words -= len + 1;
3093 if (remaining_words > 0) {
3094 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3095 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3096 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07003097 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 (len +
3099 1),
3100 GFP_KERNEL);
3101 cifs_strfromUCS_le
3102 (ses->
3103 serverDomain,
3104 (wchar_t *)
3105 bcc_ptr, len,
3106 nls_codepage);
3107 bcc_ptr +=
3108 2 * (len + 1);
3109 ses->
3110 serverDomain[2
3111 * len]
3112 = 0;
3113 ses->
3114 serverDomain[1
3115 +
3116 (2
3117 *
3118 len)]
3119 = 0;
3120 } /* else no more room so create dummy domain string */
3121 else
Steve French433dc242005-04-28 22:41:08 -07003122 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07003124 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3125 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 }
3127 } else { /* ASCII */
3128 len = strnlen(bcc_ptr, 1024);
3129 if (((long) bcc_ptr + len) -
3130 (long) pByteArea(smb_buffer_response)
3131 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07003132 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 strncpy(ses->serverOS,bcc_ptr, len);
3134
3135 bcc_ptr += len;
3136 bcc_ptr[0] = 0; /* null terminate the string */
3137 bcc_ptr++;
3138
3139 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003140 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 strncpy(ses->serverNOS, bcc_ptr, len);
3142 bcc_ptr += len;
3143 bcc_ptr[0] = 0;
3144 bcc_ptr++;
3145
3146 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003147 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 strncpy(ses->serverDomain, bcc_ptr, len);
3149 bcc_ptr += len;
3150 bcc_ptr[0] = 0;
3151 bcc_ptr++;
3152 } else
3153 cFYI(1,
3154 ("Variable field of length %d extends beyond end of smb ",
3155 len));
3156 }
3157 } else {
3158 cERROR(1,
3159 (" Security Blob Length extends beyond end of SMB"));
3160 }
3161 } else {
3162 cERROR(1, ("No session structure passed in."));
3163 }
3164 } else {
3165 cERROR(1,
3166 (" Invalid Word count %d: ",
3167 smb_buffer_response->WordCount));
3168 rc = -EIO;
3169 }
3170
3171 if (smb_buffer)
3172 cifs_buf_release(smb_buffer);
3173
3174 return rc;
3175}
3176
3177int
3178CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3179 const char *tree, struct cifsTconInfo *tcon,
3180 const struct nls_table *nls_codepage)
3181{
3182 struct smb_hdr *smb_buffer;
3183 struct smb_hdr *smb_buffer_response;
3184 TCONX_REQ *pSMB;
3185 TCONX_RSP *pSMBr;
3186 unsigned char *bcc_ptr;
3187 int rc = 0;
3188 int length;
3189 __u16 count;
3190
3191 if (ses == NULL)
3192 return -EIO;
3193
3194 smb_buffer = cifs_buf_get();
3195 if (smb_buffer == NULL) {
3196 return -ENOMEM;
3197 }
3198 smb_buffer_response = smb_buffer;
3199
3200 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3201 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003202
3203 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 smb_buffer->Uid = ses->Suid;
3205 pSMB = (TCONX_REQ *) smb_buffer;
3206 pSMBr = (TCONX_RSP *) smb_buffer_response;
3207
3208 pSMB->AndXCommand = 0xFF;
3209 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3210 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3211 bcc_ptr = &pSMB->Password[0];
3212 bcc_ptr++; /* skip password */
3213
3214 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3215 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3216
3217 if (ses->capabilities & CAP_STATUS32) {
3218 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3219 }
3220 if (ses->capabilities & CAP_DFS) {
3221 smb_buffer->Flags2 |= SMBFLG2_DFS;
3222 }
3223 if (ses->capabilities & CAP_UNICODE) {
3224 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3225 length =
3226 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3227 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3228 bcc_ptr += 2; /* skip trailing null */
3229 } else { /* ASCII */
3230
3231 strcpy(bcc_ptr, tree);
3232 bcc_ptr += strlen(tree) + 1;
3233 }
3234 strcpy(bcc_ptr, "?????");
3235 bcc_ptr += strlen("?????");
3236 bcc_ptr += 1;
3237 count = bcc_ptr - &pSMB->Password[0];
3238 pSMB->hdr.smb_buf_length += count;
3239 pSMB->ByteCount = cpu_to_le16(count);
3240
3241 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3242
3243 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3244 /* above now done in SendReceive */
3245 if ((rc == 0) && (tcon != NULL)) {
3246 tcon->tidStatus = CifsGood;
3247 tcon->tid = smb_buffer_response->Tid;
3248 bcc_ptr = pByteArea(smb_buffer_response);
3249 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3250 /* skip service field (NB: this field is always ASCII) */
3251 bcc_ptr += length + 1;
3252 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3253 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3254 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3255 if ((bcc_ptr + (2 * length)) -
3256 pByteArea(smb_buffer_response) <=
3257 BCC(smb_buffer_response)) {
3258 if(tcon->nativeFileSystem)
3259 kfree(tcon->nativeFileSystem);
3260 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003261 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 cifs_strfromUCS_le(tcon->nativeFileSystem,
3263 (wchar_t *) bcc_ptr,
3264 length, nls_codepage);
3265 bcc_ptr += 2 * length;
3266 bcc_ptr[0] = 0; /* null terminate the string */
3267 bcc_ptr[1] = 0;
3268 bcc_ptr += 2;
3269 }
3270 /* else do not bother copying these informational fields */
3271 } else {
3272 length = strnlen(bcc_ptr, 1024);
3273 if ((bcc_ptr + length) -
3274 pByteArea(smb_buffer_response) <=
3275 BCC(smb_buffer_response)) {
3276 if(tcon->nativeFileSystem)
3277 kfree(tcon->nativeFileSystem);
3278 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003279 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 strncpy(tcon->nativeFileSystem, bcc_ptr,
3281 length);
3282 }
3283 /* else do not bother copying these informational fields */
3284 }
3285 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3286 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3287 } else if ((rc == 0) && tcon == NULL) {
3288 /* all we need to save for IPC$ connection */
3289 ses->ipc_tid = smb_buffer_response->Tid;
3290 }
3291
3292 if (smb_buffer)
3293 cifs_buf_release(smb_buffer);
3294 return rc;
3295}
3296
3297int
3298cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3299{
3300 int rc = 0;
3301 int xid;
3302 struct cifsSesInfo *ses = NULL;
3303 struct task_struct *cifsd_task;
3304
3305 xid = GetXid();
3306
3307 if (cifs_sb->tcon) {
3308 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3309 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3310 if (rc == -EBUSY) {
3311 FreeXid(xid);
3312 return 0;
3313 }
3314 tconInfoFree(cifs_sb->tcon);
3315 if ((ses) && (ses->server)) {
3316 /* save off task so we do not refer to ses later */
3317 cifsd_task = ses->server->tsk;
3318 cFYI(1, ("About to do SMBLogoff "));
3319 rc = CIFSSMBLogoff(xid, ses);
3320 if (rc == -EBUSY) {
3321 FreeXid(xid);
3322 return 0;
3323 } else if (rc == -ESHUTDOWN) {
3324 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003325 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003327 wait_for_completion(&cifsd_complete);
3328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 rc = 0;
3330 } /* else - we have an smb session
3331 left on this socket do not kill cifsd */
3332 } else
3333 cFYI(1, ("No session or bad tcon"));
3334 }
3335
3336 cifs_sb->tcon = NULL;
3337 if (ses) {
3338 set_current_state(TASK_INTERRUPTIBLE);
3339 schedule_timeout(HZ / 2);
3340 }
3341 if (ses)
3342 sesInfoFree(ses);
3343
3344 FreeXid(xid);
3345 return rc; /* BB check if we should always return zero here */
3346}
3347
3348int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3349 struct nls_table * nls_info)
3350{
3351 int rc = 0;
3352 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3353 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003354 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355
3356 /* what if server changes its buffer size after dropping the session? */
3357 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3358 rc = CIFSSMBNegotiate(xid, pSesInfo);
3359 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3360 rc = CIFSSMBNegotiate(xid, pSesInfo);
3361 if(rc == -EAGAIN)
3362 rc = -EHOSTDOWN;
3363 }
3364 if(rc == 0) {
3365 spin_lock(&GlobalMid_Lock);
3366 if(pSesInfo->server->tcpStatus != CifsExiting)
3367 pSesInfo->server->tcpStatus = CifsGood;
3368 else
3369 rc = -EHOSTDOWN;
3370 spin_unlock(&GlobalMid_Lock);
3371
3372 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003373 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 }
3375 if (!rc) {
3376 pSesInfo->capabilities = pSesInfo->server->capabilities;
3377 if(linuxExtEnabled == 0)
3378 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003379 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3381 pSesInfo->server->secMode,
3382 pSesInfo->server->capabilities,
3383 pSesInfo->server->timeZone));
3384 if (extended_security
3385 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3386 && (pSesInfo->server->secType == NTLMSSP)) {
3387 cFYI(1, ("New style sesssetup "));
3388 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3389 NULL /* security blob */,
3390 0 /* blob length */,
3391 nls_info);
3392 } else if (extended_security
3393 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3394 && (pSesInfo->server->secType == RawNTLMSSP)) {
3395 cFYI(1, ("NTLMSSP sesssetup "));
3396 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3397 pSesInfo,
3398 &ntlmv2_flag,
3399 nls_info);
3400 if (!rc) {
3401 if(ntlmv2_flag) {
3402 char * v2_response;
3403 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3404 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3405 nls_info)) {
3406 rc = -ENOMEM;
3407 goto ss_err_exit;
3408 } else
3409 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3410 if(v2_response) {
3411 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003412 /* if(first_time)
3413 cifs_calculate_ntlmv2_mac_key(
3414 pSesInfo->server->mac_signing_key,
3415 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 kfree(v2_response);
3417 /* BB Put dummy sig in SessSetup PDU? */
3418 } else {
3419 rc = -ENOMEM;
3420 goto ss_err_exit;
3421 }
3422
3423 } else {
3424 SMBNTencrypt(pSesInfo->password,
3425 pSesInfo->server->cryptKey,
3426 ntlm_session_key);
3427
Steve Frenchad009ac2005-04-28 22:41:05 -07003428 if(first_time)
3429 cifs_calculate_mac_key(
3430 pSesInfo->server->mac_signing_key,
3431 ntlm_session_key,
3432 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 }
3434 /* for better security the weaker lanman hash not sent
3435 in AuthSessSetup so we no longer calculate it */
3436
3437 rc = CIFSNTLMSSPAuthSessSetup(xid,
3438 pSesInfo,
3439 ntlm_session_key,
3440 ntlmv2_flag,
3441 nls_info);
3442 }
3443 } else { /* old style NTLM 0.12 session setup */
3444 SMBNTencrypt(pSesInfo->password,
3445 pSesInfo->server->cryptKey,
3446 ntlm_session_key);
3447
Steve Frenchad009ac2005-04-28 22:41:05 -07003448 if(first_time)
3449 cifs_calculate_mac_key(
3450 pSesInfo->server->mac_signing_key,
3451 ntlm_session_key, pSesInfo->password);
3452
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 rc = CIFSSessSetup(xid, pSesInfo,
3454 ntlm_session_key, nls_info);
3455 }
3456 if (rc) {
3457 cERROR(1,("Send error in SessSetup = %d",rc));
3458 } else {
3459 cFYI(1,("CIFS Session Established successfully"));
3460 pSesInfo->status = CifsGood;
3461 }
3462 }
3463ss_err_exit:
3464 return rc;
3465}
3466