blob: 8c5d310514ea8304f719fe310fe3e236029057b7 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/uaccess.h>
33#include <asm/processor.h>
34#include "cifspdu.h"
35#include "cifsglob.h"
36#include "cifsproto.h"
37#include "cifs_unicode.h"
38#include "cifs_debug.h"
39#include "cifs_fs_sb.h"
40#include "ntlmssp.h"
41#include "nterr.h"
42#include "rfc1002pdu.h"
43
44#define CIFS_PORT 445
45#define RFC1001_PORT 139
46
47extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
48 unsigned char *p24);
49extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
50 unsigned char *p24);
51
52extern mempool_t *cifs_req_poolp;
53
54struct smb_vol {
55 char *username;
56 char *password;
57 char *domainname;
58 char *UNC;
59 char *UNCip;
60 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
61 char *iocharset; /* local code page for mapping to and from Unicode */
62 char source_rfc1001_name[16]; /* netbios name of client */
63 uid_t linux_uid;
64 gid_t linux_gid;
65 mode_t file_mode;
66 mode_t dir_mode;
67 unsigned rw:1;
68 unsigned retry:1;
69 unsigned intr:1;
70 unsigned setuids:1;
71 unsigned noperm:1;
72 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
73 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
74 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
75 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070076 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 unsigned int rsize;
78 unsigned int wsize;
79 unsigned int sockopt;
80 unsigned short int port;
81};
82
83static int ipv4_connect(struct sockaddr_in *psin_server,
84 struct socket **csocket,
85 char * netb_name);
86static int ipv6_connect(struct sockaddr_in6 *psin_server,
87 struct socket **csocket);
88
89
90 /*
91 * cifs tcp session reconnection
92 *
93 * mark tcp session as reconnecting so temporarily locked
94 * mark all smb sessions as reconnecting for tcp session
95 * reconnect tcp session
96 * wake up waiters on reconnection? - (not needed currently)
97 */
98
99int
100cifs_reconnect(struct TCP_Server_Info *server)
101{
102 int rc = 0;
103 struct list_head *tmp;
104 struct cifsSesInfo *ses;
105 struct cifsTconInfo *tcon;
106 struct mid_q_entry * mid_entry;
107
108 spin_lock(&GlobalMid_Lock);
109 if(server->tcpStatus == CifsExiting) {
110 /* the demux thread will exit normally
111 next time through the loop */
112 spin_unlock(&GlobalMid_Lock);
113 return rc;
114 } else
115 server->tcpStatus = CifsNeedReconnect;
116 spin_unlock(&GlobalMid_Lock);
117 server->maxBuf = 0;
118
119 cFYI(1, ("Reconnecting tcp session "));
120
121 /* before reconnecting the tcp session, mark the smb session (uid)
122 and the tid bad so they are not used until reconnected */
123 read_lock(&GlobalSMBSeslock);
124 list_for_each(tmp, &GlobalSMBSessionList) {
125 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
126 if (ses->server) {
127 if (ses->server == server) {
128 ses->status = CifsNeedReconnect;
129 ses->ipc_tid = 0;
130 }
131 }
132 /* else tcp and smb sessions need reconnection */
133 }
134 list_for_each(tmp, &GlobalTreeConnectionList) {
135 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
136 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
137 tcon->tidStatus = CifsNeedReconnect;
138 }
139 }
140 read_unlock(&GlobalSMBSeslock);
141 /* do not want to be sending data on a socket we are freeing */
142 down(&server->tcpSem);
143 if(server->ssocket) {
144 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
145 server->ssocket->flags));
146 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
147 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
148 server->ssocket->flags));
149 sock_release(server->ssocket);
150 server->ssocket = NULL;
151 }
152
153 spin_lock(&GlobalMid_Lock);
154 list_for_each(tmp, &server->pending_mid_q) {
155 mid_entry = list_entry(tmp, struct
156 mid_q_entry,
157 qhead);
158 if(mid_entry) {
159 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700160 /* Mark other intransit requests as needing
161 retry so we do not immediately mark the
162 session bad again (ie after we reconnect
163 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 mid_entry->midState = MID_RETRY_NEEDED;
165 }
166 }
167 }
168 spin_unlock(&GlobalMid_Lock);
169 up(&server->tcpSem);
170
171 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
172 {
173 if(server->protocolType == IPV6) {
174 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
175 } else {
176 rc = ipv4_connect(&server->addr.sockAddr,
177 &server->ssocket,
178 server->workstation_RFC1001_name);
179 }
180 if(rc) {
181 set_current_state(TASK_INTERRUPTIBLE);
182 schedule_timeout(3 * HZ);
183 } else {
184 atomic_inc(&tcpSesReconnectCount);
185 spin_lock(&GlobalMid_Lock);
186 if(server->tcpStatus != CifsExiting)
187 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700188 server->sequence_number = 0;
189 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 /* atomic_set(&server->inFlight,0);*/
191 wake_up(&server->response_q);
192 }
193 }
194 return rc;
195}
196
197static int
198cifs_demultiplex_thread(struct TCP_Server_Info *server)
199{
200 int length;
201 unsigned int pdu_length, total_read;
202 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700203 struct smb_hdr *bigbuf = NULL;
204 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 struct msghdr smb_msg;
206 struct kvec iov;
207 struct socket *csocket = server->ssocket;
208 struct list_head *tmp;
209 struct cifsSesInfo *ses;
210 struct task_struct *task_to_wake = NULL;
211 struct mid_q_entry *mid_entry;
212 char *temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700213 int isLargeBuf = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 daemonize("cifsd");
216 allow_signal(SIGKILL);
217 current->flags |= PF_MEMALLOC;
218 server->tsk = current; /* save process info to wake at shutdown */
219 cFYI(1, ("Demultiplex PID: %d", current->pid));
220 write_lock(&GlobalSMBSeslock);
221 atomic_inc(&tcpSesAllocCount);
222 length = tcpSesAllocCount.counter;
223 write_unlock(&GlobalSMBSeslock);
224 if(length > 1) {
225 mempool_resize(cifs_req_poolp,
226 length + cifs_min_rcv,
227 GFP_KERNEL);
228 }
229
230 while (server->tcpStatus != CifsExiting) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700231 if (bigbuf == NULL) {
232 bigbuf = cifs_buf_get();
233 if(bigbuf == NULL) {
234 cERROR(1,("No memory for large SMB response"));
235 msleep(3000);
236 /* retry will check if exiting */
237 continue;
238 }
239 } else if(isLargeBuf) {
240 /* we are reusing a dirtry large buf, clear its start */
241 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700243
244 if (smallbuf == NULL) {
245 smallbuf = cifs_small_buf_get();
246 if(smallbuf == NULL) {
247 cERROR(1,("No memory for SMB response"));
248 msleep(1000);
249 /* retry will check if exiting */
250 continue;
251 }
252 /* beginning of smb buffer is cleared in our buf_get */
253 } else /* if existing small buf clear beginning */
254 memset(smallbuf, 0, sizeof (struct smb_hdr));
255
256 isLargeBuf = FALSE;
257 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 iov.iov_base = smb_buffer;
259 iov.iov_len = 4;
260 smb_msg.msg_control = NULL;
261 smb_msg.msg_controllen = 0;
262 length =
263 kernel_recvmsg(csocket, &smb_msg,
264 &iov, 1, 4, 0 /* BB see socket.h flags */);
265
266 if(server->tcpStatus == CifsExiting) {
267 break;
268 } else if (server->tcpStatus == CifsNeedReconnect) {
269 cFYI(1,("Reconnecting after server stopped responding"));
270 cifs_reconnect(server);
271 cFYI(1,("call to reconnect done"));
272 csocket = server->ssocket;
273 continue;
274 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700275 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 allowing socket to clear and app threads to set
277 tcpStatus CifsNeedReconnect if server hung */
278 continue;
279 } else if (length <= 0) {
280 if(server->tcpStatus == CifsNew) {
281 cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
Steve French09d1db52005-04-28 22:41:08 -0700282 /* some servers kill the TCP session rather than
283 returning an SMB negprot error, in which
284 case reconnecting here is not going to help,
285 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 break;
287 }
288 if(length == -EINTR) {
289 cFYI(1,("cifsd thread killed"));
290 break;
291 }
292 cFYI(1,("Reconnecting after unexpected peek error %d",length));
293 cifs_reconnect(server);
294 csocket = server->ssocket;
295 wake_up(&server->response_q);
296 continue;
297 } else if (length > 3) {
298 pdu_length = ntohl(smb_buffer->smb_buf_length);
299 /* Only read pdu_length after below checks for too short (due
300 to e.g. int overflow) and too long ie beyond end of buf */
Steve French09d1db52005-04-28 22:41:08 -0700301 cFYI(1,("rfc1002 length(big endian)0x%x)",
302 pdu_length+4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 temp = (char *) smb_buffer;
305 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
306 cFYI(0,("Received 4 byte keep alive packet"));
Steve French09d1db52005-04-28 22:41:08 -0700307 } else if (temp[0] ==
308 (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 cFYI(1,("Good RFC 1002 session rsp"));
Steve French09d1db52005-04-28 22:41:08 -0700310 } else if (temp[0] ==
311 (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
312 /* we get this from Windows 98 instead of
313 an error on SMB negprot response */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
315 if(server->tcpStatus == CifsNew) {
316 /* if nack on negprot (rather than
317 ret of smb negprot error) reconnecting
318 not going to help, ret error to mount */
319 break;
320 } else {
321 /* give server a second to
322 clean up before reconnect attempt */
Steve Frenchb8643e12005-04-28 22:41:07 -0700323 msleep(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 /* always try 445 first on reconnect
325 since we get NACK on some if we ever
326 connected to port 139 (the NACK is
327 since we do not begin with RFC1001
328 session initialize frame) */
Steve French09d1db52005-04-28 22:41:08 -0700329 server->addr.sockAddr.sin_port =
330 htons(CIFS_PORT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 cifs_reconnect(server);
332 csocket = server->ssocket;
333 wake_up(&server->response_q);
334 continue;
335 }
336 } else if (temp[0] != (char) 0) {
337 cERROR(1,("Unknown RFC 1002 frame"));
338 cifs_dump_mem(" Received Data: ", temp, length);
339 cifs_reconnect(server);
340 csocket = server->ssocket;
341 continue;
342 } else {
Steve French09d1db52005-04-28 22:41:08 -0700343 if((pdu_length > CIFSMaxBufSize +
344 MAX_CIFS_HDR_SIZE - 4) ||
345 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 cERROR(1,
347 ("Invalid size SMB length %d and pdu_length %d",
348 length, pdu_length+4));
349 cifs_reconnect(server);
350 csocket = server->ssocket;
351 wake_up(&server->response_q);
352 continue;
353 } else { /* length ok */
Steve Frenchb8643e12005-04-28 22:41:07 -0700354 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
355 isLargeBuf = TRUE;
356 memcpy(bigbuf, smallbuf, 4);
357 smb_buffer = bigbuf;
358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 length = 0;
360 iov.iov_base = 4 + (char *)smb_buffer;
361 iov.iov_len = pdu_length;
Steve French67010fb2005-04-28 22:41:09 -0700362 for (total_read = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 total_read < pdu_length;
364 total_read += length) {
Steve French67010fb2005-04-28 22:41:09 -0700365 length = kernel_recvmsg(csocket, &smb_msg,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 &iov, 1,
367 pdu_length - total_read, 0);
Steve French67010fb2005-04-28 22:41:09 -0700368 if((server->tcpStatus == CifsExiting) ||
369 (length == -EINTR)) {
370 /* then will exit */
371 goto dmx_loop_end;
372 } else if (server->tcpStatus ==
373 CifsNeedReconnect) {
374 cifs_reconnect(server);
375 csocket = server->ssocket;
376 /* Reconnect wakes up rspns q */
377 /* Now we will reread sock */
378 goto dmx_loop_end;
379 } else if ((length == -ERESTARTSYS) ||
380 (length == -EAGAIN)) {
381 msleep(1); /* minimum sleep to prevent looping
382 allowing socket to clear and app threads to set
383 tcpStatus CifsNeedReconnect if server hung */
384 continue;
385 } else if (length <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 cERROR(1,
Steve French67010fb2005-04-28 22:41:09 -0700387 ("Received no data, expecting %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 pdu_length - total_read));
389 cifs_reconnect(server);
390 csocket = server->ssocket;
Steve French67010fb2005-04-28 22:41:09 -0700391 goto dmx_loop_end;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
393 }
394 length += 4; /* account for rfc1002 hdr */
395 }
396
397 dump_smb(smb_buffer, length);
398 if (checkSMB
399 (smb_buffer, smb_buffer->Mid, total_read+4)) {
400 cERROR(1, ("Bad SMB Received "));
401 continue;
402 }
403
Steve French09d1db52005-04-28 22:41:08 -0700404 /* BB FIXME - add checkTrans2SMBSecondary() */
405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 task_to_wake = NULL;
407 spin_lock(&GlobalMid_Lock);
408 list_for_each(tmp, &server->pending_mid_q) {
409 mid_entry = list_entry(tmp, struct
410 mid_q_entry,
411 qhead);
412
Steve French848f3fc2005-04-28 22:41:07 -0700413 if ((mid_entry->mid == smb_buffer->Mid)
414 && (mid_entry->midState ==
415 MID_REQUEST_SUBMITTED)
416 && (mid_entry->command ==
417 smb_buffer->Command)) {
418 cFYI(1,("Found Mid 0x%x wake up"
419 ,mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 task_to_wake = mid_entry->tsk;
421 mid_entry->resp_buf =
422 smb_buffer;
423 mid_entry->midState =
424 MID_RESPONSE_RECEIVED;
Steve French099a58f2005-04-28 22:41:07 -0700425 if(isLargeBuf)
426 mid_entry->largeBuf = 1;
427 else
428 mid_entry->largeBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 }
430 }
431 spin_unlock(&GlobalMid_Lock);
432 if (task_to_wake) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700433 if(isLargeBuf)
434 bigbuf = NULL;
435 else
436 smallbuf = NULL;
Steve French09d1db52005-04-28 22:41:08 -0700437 smb_buffer = NULL; /* will be freed by users thread after he is done */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 wake_up_process(task_to_wake);
439 } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
440 cERROR(1, ("No task to wake, unknown frame rcvd!"));
441 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
442 }
443 }
444 } else {
445 cFYI(1,
446 ("Frame less than four bytes received %d bytes long.",
447 length));
448 cifs_reconnect(server);
449 csocket = server->ssocket;
450 wake_up(&server->response_q);
451 continue;
452 }
Steve French67010fb2005-04-28 22:41:09 -0700453dmx_loop_end:
454 cFYI(1,("Exiting cifsd loop"));
455
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
457 spin_lock(&GlobalMid_Lock);
458 server->tcpStatus = CifsExiting;
459 server->tsk = NULL;
460 atomic_set(&server->inFlight, 0);
461 spin_unlock(&GlobalMid_Lock);
462 /* Although there should not be any requests blocked on
463 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700464 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 to the same server - they now will see the session is in exit state
466 and get out of SendReceive. */
467 wake_up_all(&server->request_q);
468 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700469 msleep(125);
470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if(server->ssocket) {
472 sock_release(csocket);
473 server->ssocket = NULL;
474 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700475 /* buffer usuallly freed in free_mid - need to free it here on exit */
476 if (bigbuf != NULL)
477 cifs_buf_release(bigbuf);
478 if (smallbuf != NULL)
479 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
481 read_lock(&GlobalSMBSeslock);
482 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700483 /* loop through server session structures attached to this and
484 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 list_for_each(tmp, &GlobalSMBSessionList) {
486 ses =
487 list_entry(tmp, struct cifsSesInfo,
488 cifsSessionList);
489 if (ses->server == server) {
490 ses->status = CifsExiting;
491 ses->server = NULL;
492 }
493 }
494 read_unlock(&GlobalSMBSeslock);
495 } else {
496 spin_lock(&GlobalMid_Lock);
497 list_for_each(tmp, &server->pending_mid_q) {
498 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
499 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
500 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700501 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 task_to_wake = mid_entry->tsk;
503 if(task_to_wake) {
504 wake_up_process(task_to_wake);
505 }
506 }
507 }
508 spin_unlock(&GlobalMid_Lock);
509 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700511 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
513
514 if (list_empty(&server->pending_mid_q)) {
515 /* mpx threads have not exited yet give them
516 at least the smb send timeout time for long ops */
517 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700518 msleep(46);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 /* if threads still have not exited they are probably never
520 coming home not much else we can do but free the memory */
521 }
522 kfree(server);
523
524 write_lock(&GlobalSMBSeslock);
525 atomic_dec(&tcpSesAllocCount);
526 length = tcpSesAllocCount.counter;
527 write_unlock(&GlobalSMBSeslock);
528 if(length > 0) {
529 mempool_resize(cifs_req_poolp,
530 length + cifs_min_rcv,
531 GFP_KERNEL);
532 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700533
534 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return 0;
536}
537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538static int
539cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
540{
541 char *value;
542 char *data;
543 unsigned int temp_len, i, j;
544 char separator[2];
545
546 separator[0] = ',';
547 separator[1] = 0;
548
549 memset(vol->source_rfc1001_name,0x20,15);
550 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
551 /* does not have to be a perfect mapping since the field is
552 informational, only used for servers that do not support
553 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700554 vol->source_rfc1001_name[i] =
555 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
557 vol->source_rfc1001_name[15] = 0;
558
559 vol->linux_uid = current->uid; /* current->euid instead? */
560 vol->linux_gid = current->gid;
561 vol->dir_mode = S_IRWXUGO;
562 /* 2767 perms indicate mandatory locking support */
563 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
564
565 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
566 vol->rw = TRUE;
567
568 if (!options)
569 return 1;
570
571 if(strncmp(options,"sep=",4) == 0) {
572 if(options[4] != 0) {
573 separator[0] = options[4];
574 options += 5;
575 } else {
576 cFYI(1,("Null separator not allowed"));
577 }
578 }
579
580 while ((data = strsep(&options, separator)) != NULL) {
581 if (!*data)
582 continue;
583 if ((value = strchr(data, '=')) != NULL)
584 *value++ = '\0';
585
586 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
587 vol->no_xattr = 0;
588 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
589 vol->no_xattr = 1;
590 } else if (strnicmp(data, "user", 4) == 0) {
591 if (!value || !*value) {
592 printk(KERN_WARNING
593 "CIFS: invalid or missing username\n");
594 return 1; /* needs_arg; */
595 }
596 if (strnlen(value, 200) < 200) {
597 vol->username = value;
598 } else {
599 printk(KERN_WARNING "CIFS: username too long\n");
600 return 1;
601 }
602 } else if (strnicmp(data, "pass", 4) == 0) {
603 if (!value) {
604 vol->password = NULL;
605 continue;
606 } else if(value[0] == 0) {
607 /* check if string begins with double comma
608 since that would mean the password really
609 does start with a comma, and would not
610 indicate an empty string */
611 if(value[1] != separator[0]) {
612 vol->password = NULL;
613 continue;
614 }
615 }
616 temp_len = strlen(value);
617 /* removed password length check, NTLM passwords
618 can be arbitrarily long */
619
620 /* if comma in password, the string will be
621 prematurely null terminated. Commas in password are
622 specified across the cifs mount interface by a double
623 comma ie ,, and a comma used as in other cases ie ','
624 as a parameter delimiter/separator is single and due
625 to the strsep above is temporarily zeroed. */
626
627 /* NB: password legally can have multiple commas and
628 the only illegal character in a password is null */
629
Steve French09d1db52005-04-28 22:41:08 -0700630 if ((value[temp_len] == 0) &&
631 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 /* reinsert comma */
633 value[temp_len] = separator[0];
634 temp_len+=2; /* move after the second comma */
635 while(value[temp_len] != 0) {
636 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700637 if (value[temp_len+1] ==
638 separator[0]) {
639 /* skip second comma */
640 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 } else {
642 /* single comma indicating start
643 of next parm */
644 break;
645 }
646 }
647 temp_len++;
648 }
649 if(value[temp_len] == 0) {
650 options = NULL;
651 } else {
652 value[temp_len] = 0;
653 /* point option to start of next parm */
654 options = value + temp_len + 1;
655 }
656 /* go from value to value + temp_len condensing
657 double commas to singles. Note that this ends up
658 allocating a few bytes too many, which is ok */
Steve French433dc242005-04-28 22:41:08 -0700659 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
660 if(vol->password == NULL) {
661 printk("CIFS: no memory for pass\n");
662 return 1;
663 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 for(i=0,j=0;i<temp_len;i++,j++) {
665 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700666 if(value[i] == separator[0]
667 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 /* skip second comma */
669 i++;
670 }
671 }
672 vol->password[j] = 0;
673 } else {
Steve French09d1db52005-04-28 22:41:08 -0700674 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700675 if(vol->password == NULL) {
676 printk("CIFS: no memory for pass\n");
677 return 1;
678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 strcpy(vol->password, value);
680 }
681 } else if (strnicmp(data, "ip", 2) == 0) {
682 if (!value || !*value) {
683 vol->UNCip = NULL;
684 } else if (strnlen(value, 35) < 35) {
685 vol->UNCip = value;
686 } else {
687 printk(KERN_WARNING "CIFS: ip address too long\n");
688 return 1;
689 }
690 } else if ((strnicmp(data, "unc", 3) == 0)
691 || (strnicmp(data, "target", 6) == 0)
692 || (strnicmp(data, "path", 4) == 0)) {
693 if (!value || !*value) {
694 printk(KERN_WARNING
695 "CIFS: invalid path to network resource\n");
696 return 1; /* needs_arg; */
697 }
698 if ((temp_len = strnlen(value, 300)) < 300) {
699 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
700 if(vol->UNC == NULL)
701 return 1;
702 strcpy(vol->UNC,value);
703 if (strncmp(vol->UNC, "//", 2) == 0) {
704 vol->UNC[0] = '\\';
705 vol->UNC[1] = '\\';
706 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
707 printk(KERN_WARNING
708 "CIFS: UNC Path does not begin with // or \\\\ \n");
709 return 1;
710 }
711 } else {
712 printk(KERN_WARNING "CIFS: UNC name too long\n");
713 return 1;
714 }
715 } else if ((strnicmp(data, "domain", 3) == 0)
716 || (strnicmp(data, "workgroup", 5) == 0)) {
717 if (!value || !*value) {
718 printk(KERN_WARNING "CIFS: invalid domain name\n");
719 return 1; /* needs_arg; */
720 }
721 /* BB are there cases in which a comma can be valid in
722 a domain name and need special handling? */
723 if (strnlen(value, 65) < 65) {
724 vol->domainname = value;
725 cFYI(1, ("Domain name set"));
726 } else {
727 printk(KERN_WARNING "CIFS: domain name too long\n");
728 return 1;
729 }
730 } else if (strnicmp(data, "iocharset", 9) == 0) {
731 if (!value || !*value) {
732 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
733 return 1; /* needs_arg; */
734 }
735 if (strnlen(value, 65) < 65) {
736 if(strnicmp(value,"default",7))
737 vol->iocharset = value;
738 /* if iocharset not set load_nls_default used by caller */
739 cFYI(1, ("iocharset set to %s",value));
740 } else {
741 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
742 return 1;
743 }
744 } else if (strnicmp(data, "uid", 3) == 0) {
745 if (value && *value) {
746 vol->linux_uid =
747 simple_strtoul(value, &value, 0);
748 }
749 } else if (strnicmp(data, "gid", 3) == 0) {
750 if (value && *value) {
751 vol->linux_gid =
752 simple_strtoul(value, &value, 0);
753 }
754 } else if (strnicmp(data, "file_mode", 4) == 0) {
755 if (value && *value) {
756 vol->file_mode =
757 simple_strtoul(value, &value, 0);
758 }
759 } else if (strnicmp(data, "dir_mode", 4) == 0) {
760 if (value && *value) {
761 vol->dir_mode =
762 simple_strtoul(value, &value, 0);
763 }
764 } else if (strnicmp(data, "dirmode", 4) == 0) {
765 if (value && *value) {
766 vol->dir_mode =
767 simple_strtoul(value, &value, 0);
768 }
769 } else if (strnicmp(data, "port", 4) == 0) {
770 if (value && *value) {
771 vol->port =
772 simple_strtoul(value, &value, 0);
773 }
774 } else if (strnicmp(data, "rsize", 5) == 0) {
775 if (value && *value) {
776 vol->rsize =
777 simple_strtoul(value, &value, 0);
778 }
779 } else if (strnicmp(data, "wsize", 5) == 0) {
780 if (value && *value) {
781 vol->wsize =
782 simple_strtoul(value, &value, 0);
783 }
784 } else if (strnicmp(data, "sockopt", 5) == 0) {
785 if (value && *value) {
786 vol->sockopt =
787 simple_strtoul(value, &value, 0);
788 }
789 } else if (strnicmp(data, "netbiosname", 4) == 0) {
790 if (!value || !*value || (*value == ' ')) {
791 cFYI(1,("invalid (empty) netbiosname specified"));
792 } else {
793 memset(vol->source_rfc1001_name,0x20,15);
794 for(i=0;i<15;i++) {
795 /* BB are there cases in which a comma can be
796 valid in this workstation netbios name (and need
797 special handling)? */
798
799 /* We do not uppercase netbiosname for user */
800 if (value[i]==0)
801 break;
802 else
803 vol->source_rfc1001_name[i] = value[i];
804 }
805 /* The string has 16th byte zero still from
806 set at top of the function */
807 if((i==15) && (value[i] != 0))
808 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
809 }
810 } else if (strnicmp(data, "credentials", 4) == 0) {
811 /* ignore */
812 } else if (strnicmp(data, "version", 3) == 0) {
813 /* ignore */
814 } else if (strnicmp(data, "guest",5) == 0) {
815 /* ignore */
816 } else if (strnicmp(data, "rw", 2) == 0) {
817 vol->rw = TRUE;
818 } else if ((strnicmp(data, "suid", 4) == 0) ||
819 (strnicmp(data, "nosuid", 6) == 0) ||
820 (strnicmp(data, "exec", 4) == 0) ||
821 (strnicmp(data, "noexec", 6) == 0) ||
822 (strnicmp(data, "nodev", 5) == 0) ||
823 (strnicmp(data, "noauto", 6) == 0) ||
824 (strnicmp(data, "dev", 3) == 0)) {
825 /* The mount tool or mount.cifs helper (if present)
826 uses these opts to set flags, and the flags are read
827 by the kernel vfs layer before we get here (ie
828 before read super) so there is no point trying to
829 parse these options again and set anything and it
830 is ok to just ignore them */
831 continue;
832 } else if (strnicmp(data, "ro", 2) == 0) {
833 vol->rw = FALSE;
834 } else if (strnicmp(data, "hard", 4) == 0) {
835 vol->retry = 1;
836 } else if (strnicmp(data, "soft", 4) == 0) {
837 vol->retry = 0;
838 } else if (strnicmp(data, "perm", 4) == 0) {
839 vol->noperm = 0;
840 } else if (strnicmp(data, "noperm", 6) == 0) {
841 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -0700842 } else if (strnicmp(data, "mapchars", 8) == 0) {
843 vol->remap = 1;
844 } else if (strnicmp(data, "nomapchars", 10) == 0) {
845 vol->remap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 } else if (strnicmp(data, "setuids", 7) == 0) {
847 vol->setuids = 1;
848 } else if (strnicmp(data, "nosetuids", 9) == 0) {
849 vol->setuids = 0;
850 } else if (strnicmp(data, "nohard", 6) == 0) {
851 vol->retry = 0;
852 } else if (strnicmp(data, "nosoft", 6) == 0) {
853 vol->retry = 1;
854 } else if (strnicmp(data, "nointr", 6) == 0) {
855 vol->intr = 0;
856 } else if (strnicmp(data, "intr", 4) == 0) {
857 vol->intr = 1;
858 } else if (strnicmp(data, "serverino",7) == 0) {
859 vol->server_ino = 1;
860 } else if (strnicmp(data, "noserverino",9) == 0) {
861 vol->server_ino = 0;
862 } else if (strnicmp(data, "acl",3) == 0) {
863 vol->no_psx_acl = 0;
864 } else if (strnicmp(data, "noacl",5) == 0) {
865 vol->no_psx_acl = 1;
866 } else if (strnicmp(data, "direct",6) == 0) {
867 vol->direct_io = 1;
868 } else if (strnicmp(data, "forcedirectio",13) == 0) {
869 vol->direct_io = 1;
870 } else if (strnicmp(data, "in6_addr",8) == 0) {
871 if (!value || !*value) {
872 vol->in6_addr = NULL;
873 } else if (strnlen(value, 49) == 48) {
874 vol->in6_addr = value;
875 } else {
876 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
877 return 1;
878 }
879 } else if (strnicmp(data, "noac", 4) == 0) {
880 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
881 } else
882 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
883 }
884 if (vol->UNC == NULL) {
885 if(devname == NULL) {
886 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
887 return 1;
888 }
889 if ((temp_len = strnlen(devname, 300)) < 300) {
890 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
891 if(vol->UNC == NULL)
892 return 1;
893 strcpy(vol->UNC,devname);
894 if (strncmp(vol->UNC, "//", 2) == 0) {
895 vol->UNC[0] = '\\';
896 vol->UNC[1] = '\\';
897 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
898 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
899 return 1;
900 }
901 } else {
902 printk(KERN_WARNING "CIFS: UNC name too long\n");
903 return 1;
904 }
905 }
906 if(vol->UNCip == NULL)
907 vol->UNCip = &vol->UNC[2];
908
909 return 0;
910}
911
912static struct cifsSesInfo *
913cifs_find_tcp_session(struct in_addr * target_ip_addr,
914 struct in6_addr *target_ip6_addr,
915 char *userName, struct TCP_Server_Info **psrvTcp)
916{
917 struct list_head *tmp;
918 struct cifsSesInfo *ses;
919 *psrvTcp = NULL;
920 read_lock(&GlobalSMBSeslock);
921
922 list_for_each(tmp, &GlobalSMBSessionList) {
923 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
924 if (ses->server) {
925 if((target_ip_addr &&
926 (ses->server->addr.sockAddr.sin_addr.s_addr
927 == target_ip_addr->s_addr)) || (target_ip6_addr
928 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
929 target_ip6_addr,sizeof(*target_ip6_addr)))){
930 /* BB lock server and tcp session and increment use count here?? */
931 *psrvTcp = ses->server; /* found a match on the TCP session */
932 /* BB check if reconnection needed */
933 if (strncmp
934 (ses->userName, userName,
935 MAX_USERNAME_SIZE) == 0){
936 read_unlock(&GlobalSMBSeslock);
937 return ses; /* found exact match on both tcp and SMB sessions */
938 }
939 }
940 }
941 /* else tcp and smb sessions need reconnection */
942 }
943 read_unlock(&GlobalSMBSeslock);
944 return NULL;
945}
946
947static struct cifsTconInfo *
948find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
949{
950 struct list_head *tmp;
951 struct cifsTconInfo *tcon;
952
953 read_lock(&GlobalSMBSeslock);
954 list_for_each(tmp, &GlobalTreeConnectionList) {
955 cFYI(1, ("Next tcon - "));
956 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
957 if (tcon->ses) {
958 if (tcon->ses->server) {
959 cFYI(1,
960 (" old ip addr: %x == new ip %x ?",
961 tcon->ses->server->addr.sockAddr.sin_addr.
962 s_addr, new_target_ip_addr));
963 if (tcon->ses->server->addr.sockAddr.sin_addr.
964 s_addr == new_target_ip_addr) {
965 /* BB lock tcon and server and tcp session and increment use count here? */
966 /* found a match on the TCP session */
967 /* BB check if reconnection needed */
968 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
969 tcon->treeName, uncName));
970 if (strncmp
971 (tcon->treeName, uncName,
972 MAX_TREE_SIZE) == 0) {
973 cFYI(1,
974 ("Matched UNC, old user: %s == new: %s ?",
975 tcon->treeName, uncName));
976 if (strncmp
977 (tcon->ses->userName,
978 userName,
979 MAX_USERNAME_SIZE) == 0) {
980 read_unlock(&GlobalSMBSeslock);
981 return tcon;/* also matched user (smb session)*/
982 }
983 }
984 }
985 }
986 }
987 }
988 read_unlock(&GlobalSMBSeslock);
989 return NULL;
990}
991
992int
993connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -0700994 const char *old_path, const struct nls_table *nls_codepage,
995 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996{
997 unsigned char *referrals = NULL;
998 unsigned int num_referrals;
999 int rc = 0;
1000
1001 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001002 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 /* BB Add in code to: if valid refrl, if not ip address contact
1005 the helper that resolves tcp names, mount to it, try to
1006 tcon to it unmount it if fail */
1007
1008 if(referrals)
1009 kfree(referrals);
1010
1011 return rc;
1012}
1013
1014int
1015get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1016 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001017 unsigned int *pnum_referrals,
1018 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019{
1020 char *temp_unc;
1021 int rc = 0;
1022
1023 *pnum_referrals = 0;
1024
1025 if (pSesInfo->ipc_tid == 0) {
1026 temp_unc = kmalloc(2 /* for slashes */ +
1027 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1028 + 1 + 4 /* slash IPC$ */ + 2,
1029 GFP_KERNEL);
1030 if (temp_unc == NULL)
1031 return -ENOMEM;
1032 temp_unc[0] = '\\';
1033 temp_unc[1] = '\\';
1034 strcpy(temp_unc + 2, pSesInfo->serverName);
1035 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1036 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1037 cFYI(1,
1038 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1039 kfree(temp_unc);
1040 }
1041 if (rc == 0)
1042 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001043 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 return rc;
1046}
1047
1048/* See RFC1001 section 14 on representation of Netbios names */
1049static void rfc1002mangle(char * target,char * source, unsigned int length)
1050{
1051 unsigned int i,j;
1052
1053 for(i=0,j=0;i<(length);i++) {
1054 /* mask a nibble at a time and encode */
1055 target[j] = 'A' + (0x0F & (source[i] >> 4));
1056 target[j+1] = 'A' + (0x0F & source[i]);
1057 j+=2;
1058 }
1059
1060}
1061
1062
1063static int
1064ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1065 char * netbios_name)
1066{
1067 int rc = 0;
1068 int connected = 0;
1069 __be16 orig_port = 0;
1070
1071 if(*csocket == NULL) {
1072 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1073 if (rc < 0) {
1074 cERROR(1, ("Error %d creating socket",rc));
1075 *csocket = NULL;
1076 return rc;
1077 } else {
1078 /* BB other socket options to set KEEPALIVE, NODELAY? */
1079 cFYI(1,("Socket created"));
1080 (*csocket)->sk->sk_allocation = GFP_NOFS;
1081 }
1082 }
1083
1084 psin_server->sin_family = AF_INET;
1085 if(psin_server->sin_port) { /* user overrode default port */
1086 rc = (*csocket)->ops->connect(*csocket,
1087 (struct sockaddr *) psin_server,
1088 sizeof (struct sockaddr_in),0);
1089 if (rc >= 0)
1090 connected = 1;
1091 }
1092
1093 if(!connected) {
1094 /* save original port so we can retry user specified port
1095 later if fall back ports fail this time */
1096 orig_port = psin_server->sin_port;
1097
1098 /* do not retry on the same port we just failed on */
1099 if(psin_server->sin_port != htons(CIFS_PORT)) {
1100 psin_server->sin_port = htons(CIFS_PORT);
1101
1102 rc = (*csocket)->ops->connect(*csocket,
1103 (struct sockaddr *) psin_server,
1104 sizeof (struct sockaddr_in),0);
1105 if (rc >= 0)
1106 connected = 1;
1107 }
1108 }
1109 if (!connected) {
1110 psin_server->sin_port = htons(RFC1001_PORT);
1111 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1112 psin_server, sizeof (struct sockaddr_in),0);
1113 if (rc >= 0)
1114 connected = 1;
1115 }
1116
1117 /* give up here - unless we want to retry on different
1118 protocol families some day */
1119 if (!connected) {
1120 if(orig_port)
1121 psin_server->sin_port = orig_port;
1122 cFYI(1,("Error %d connecting to server via ipv4",rc));
1123 sock_release(*csocket);
1124 *csocket = NULL;
1125 return rc;
1126 }
1127 /* Eventually check for other socket options to change from
1128 the default. sock_setsockopt not used because it expects
1129 user space buffer */
1130 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1131
1132 /* send RFC1001 sessinit */
1133
1134 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1135 /* some servers require RFC1001 sessinit before sending
1136 negprot - BB check reconnection in case where second
1137 sessinit is sent but no second negprot */
1138 struct rfc1002_session_packet * ses_init_buf;
1139 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001140 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 if(ses_init_buf) {
1142 ses_init_buf->trailer.session_req.called_len = 32;
1143 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1144 DEFAULT_CIFS_CALLED_NAME,16);
1145 ses_init_buf->trailer.session_req.calling_len = 32;
1146 /* calling name ends in null (byte 16) from old smb
1147 convention. */
1148 if(netbios_name && (netbios_name[0] !=0)) {
1149 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1150 netbios_name,16);
1151 } else {
1152 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1153 "LINUX_CIFS_CLNT",16);
1154 }
1155 ses_init_buf->trailer.session_req.scope1 = 0;
1156 ses_init_buf->trailer.session_req.scope2 = 0;
1157 smb_buf = (struct smb_hdr *)ses_init_buf;
1158 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1159 smb_buf->smb_buf_length = 0x81000044;
1160 rc = smb_send(*csocket, smb_buf, 0x44,
1161 (struct sockaddr *)psin_server);
1162 kfree(ses_init_buf);
1163 }
1164 /* else the negprot may still work without this
1165 even though malloc failed */
1166
1167 }
1168
1169 return rc;
1170}
1171
1172static int
1173ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1174{
1175 int rc = 0;
1176 int connected = 0;
1177 __be16 orig_port = 0;
1178
1179 if(*csocket == NULL) {
1180 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1181 if (rc < 0) {
1182 cERROR(1, ("Error %d creating ipv6 socket",rc));
1183 *csocket = NULL;
1184 return rc;
1185 } else {
1186 /* BB other socket options to set KEEPALIVE, NODELAY? */
1187 cFYI(1,("ipv6 Socket created"));
1188 (*csocket)->sk->sk_allocation = GFP_NOFS;
1189 }
1190 }
1191
1192 psin_server->sin6_family = AF_INET6;
1193
1194 if(psin_server->sin6_port) { /* user overrode default port */
1195 rc = (*csocket)->ops->connect(*csocket,
1196 (struct sockaddr *) psin_server,
1197 sizeof (struct sockaddr_in6),0);
1198 if (rc >= 0)
1199 connected = 1;
1200 }
1201
1202 if(!connected) {
1203 /* save original port so we can retry user specified port
1204 later if fall back ports fail this time */
1205
1206 orig_port = psin_server->sin6_port;
1207 /* do not retry on the same port we just failed on */
1208 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1209 psin_server->sin6_port = htons(CIFS_PORT);
1210
1211 rc = (*csocket)->ops->connect(*csocket,
1212 (struct sockaddr *) psin_server,
1213 sizeof (struct sockaddr_in6),0);
1214 if (rc >= 0)
1215 connected = 1;
1216 }
1217 }
1218 if (!connected) {
1219 psin_server->sin6_port = htons(RFC1001_PORT);
1220 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1221 psin_server, sizeof (struct sockaddr_in6),0);
1222 if (rc >= 0)
1223 connected = 1;
1224 }
1225
1226 /* give up here - unless we want to retry on different
1227 protocol families some day */
1228 if (!connected) {
1229 if(orig_port)
1230 psin_server->sin6_port = orig_port;
1231 cFYI(1,("Error %d connecting to server via ipv6",rc));
1232 sock_release(*csocket);
1233 *csocket = NULL;
1234 return rc;
1235 }
1236 /* Eventually check for other socket options to change from
1237 the default. sock_setsockopt not used because it expects
1238 user space buffer */
1239 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1240
1241 return rc;
1242}
1243
1244int
1245cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1246 char *mount_data, const char *devname)
1247{
1248 int rc = 0;
1249 int xid;
1250 int address_type = AF_INET;
1251 struct socket *csocket = NULL;
1252 struct sockaddr_in sin_server;
1253 struct sockaddr_in6 sin_server6;
1254 struct smb_vol volume_info;
1255 struct cifsSesInfo *pSesInfo = NULL;
1256 struct cifsSesInfo *existingCifsSes = NULL;
1257 struct cifsTconInfo *tcon = NULL;
1258 struct TCP_Server_Info *srvTcp = NULL;
1259
1260 xid = GetXid();
1261
1262/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1263
1264 memset(&volume_info,0,sizeof(struct smb_vol));
1265 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1266 if(volume_info.UNC)
1267 kfree(volume_info.UNC);
1268 if(volume_info.password)
1269 kfree(volume_info.password);
1270 FreeXid(xid);
1271 return -EINVAL;
1272 }
1273
1274 if (volume_info.username) {
1275 /* BB fixme parse for domain name here */
1276 cFYI(1, ("Username: %s ", volume_info.username));
1277
1278 } else {
1279 cifserror("No username specified ");
1280 /* In userspace mount helper we can get user name from alternate
1281 locations such as env variables and files on disk */
1282 if(volume_info.UNC)
1283 kfree(volume_info.UNC);
1284 if(volume_info.password)
1285 kfree(volume_info.password);
1286 FreeXid(xid);
1287 return -EINVAL;
1288 }
1289
1290 if (volume_info.UNCip && volume_info.UNC) {
1291 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1292
1293 if(rc <= 0) {
1294 /* not ipv4 address, try ipv6 */
1295 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1296 if(rc > 0)
1297 address_type = AF_INET6;
1298 } else {
1299 address_type = AF_INET;
1300 }
1301
1302 if(rc <= 0) {
1303 /* we failed translating address */
1304 if(volume_info.UNC)
1305 kfree(volume_info.UNC);
1306 if(volume_info.password)
1307 kfree(volume_info.password);
1308 FreeXid(xid);
1309 return -EINVAL;
1310 }
1311
1312 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1313 /* success */
1314 rc = 0;
1315 } else if (volume_info.UNCip){
1316 /* BB using ip addr as server name connect to the DFS root below */
1317 cERROR(1,("Connecting to DFS root not implemented yet"));
1318 if(volume_info.UNC)
1319 kfree(volume_info.UNC);
1320 if(volume_info.password)
1321 kfree(volume_info.password);
1322 FreeXid(xid);
1323 return -EINVAL;
1324 } else /* which servers DFS root would we conect to */ {
1325 cERROR(1,
1326 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1327 if(volume_info.UNC)
1328 kfree(volume_info.UNC);
1329 if(volume_info.password)
1330 kfree(volume_info.password);
1331 FreeXid(xid);
1332 return -EINVAL;
1333 }
1334
1335 /* this is needed for ASCII cp to Unicode converts */
1336 if(volume_info.iocharset == NULL) {
1337 cifs_sb->local_nls = load_nls_default();
1338 /* load_nls_default can not return null */
1339 } else {
1340 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1341 if(cifs_sb->local_nls == NULL) {
1342 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1343 if(volume_info.UNC)
1344 kfree(volume_info.UNC);
1345 if(volume_info.password)
1346 kfree(volume_info.password);
1347 FreeXid(xid);
1348 return -ELIBACC;
1349 }
1350 }
1351
1352 if(address_type == AF_INET)
1353 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1354 NULL /* no ipv6 addr */,
1355 volume_info.username, &srvTcp);
1356 else if(address_type == AF_INET6)
1357 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1358 &sin_server6.sin6_addr,
1359 volume_info.username, &srvTcp);
1360 else {
1361 if(volume_info.UNC)
1362 kfree(volume_info.UNC);
1363 if(volume_info.password)
1364 kfree(volume_info.password);
1365 FreeXid(xid);
1366 return -EINVAL;
1367 }
1368
1369
1370 if (srvTcp) {
1371 cFYI(1, ("Existing tcp session with server found "));
1372 } else { /* create socket */
1373 if(volume_info.port)
1374 sin_server.sin_port = htons(volume_info.port);
1375 else
1376 sin_server.sin_port = 0;
1377 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1378 if (rc < 0) {
1379 cERROR(1,
1380 ("Error connecting to IPv4 socket. Aborting operation"));
1381 if(csocket != NULL)
1382 sock_release(csocket);
1383 if(volume_info.UNC)
1384 kfree(volume_info.UNC);
1385 if(volume_info.password)
1386 kfree(volume_info.password);
1387 FreeXid(xid);
1388 return rc;
1389 }
1390
1391 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1392 if (srvTcp == NULL) {
1393 rc = -ENOMEM;
1394 sock_release(csocket);
1395 if(volume_info.UNC)
1396 kfree(volume_info.UNC);
1397 if(volume_info.password)
1398 kfree(volume_info.password);
1399 FreeXid(xid);
1400 return rc;
1401 } else {
1402 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1403 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1404 atomic_set(&srvTcp->inFlight,0);
1405 /* BB Add code for ipv6 case too */
1406 srvTcp->ssocket = csocket;
1407 srvTcp->protocolType = IPV4;
1408 init_waitqueue_head(&srvTcp->response_q);
1409 init_waitqueue_head(&srvTcp->request_q);
1410 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1411 /* at this point we are the only ones with the pointer
1412 to the struct since the kernel thread not created yet
1413 so no need to spinlock this init of tcpStatus */
1414 srvTcp->tcpStatus = CifsNew;
1415 init_MUTEX(&srvTcp->tcpSem);
1416 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1417 CLONE_FS | CLONE_FILES | CLONE_VM);
1418 if(rc < 0) {
1419 rc = -ENOMEM;
1420 sock_release(csocket);
1421 if(volume_info.UNC)
1422 kfree(volume_info.UNC);
1423 if(volume_info.password)
1424 kfree(volume_info.password);
1425 FreeXid(xid);
1426 return rc;
1427 } else
1428 rc = 0;
1429 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001430 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 }
1432 }
1433
1434 if (existingCifsSes) {
1435 pSesInfo = existingCifsSes;
1436 cFYI(1, ("Existing smb sess found "));
1437 if(volume_info.password)
1438 kfree(volume_info.password);
1439 /* volume_info.UNC freed at end of function */
1440 } else if (!rc) {
1441 cFYI(1, ("Existing smb sess not found "));
1442 pSesInfo = sesInfoAlloc();
1443 if (pSesInfo == NULL)
1444 rc = -ENOMEM;
1445 else {
1446 pSesInfo->server = srvTcp;
1447 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1448 NIPQUAD(sin_server.sin_addr.s_addr));
1449 }
1450
1451 if (!rc){
1452 /* volume_info.password freed at unmount */
1453 if (volume_info.password)
1454 pSesInfo->password = volume_info.password;
1455 if (volume_info.username)
1456 strncpy(pSesInfo->userName,
1457 volume_info.username,MAX_USERNAME_SIZE);
1458 if (volume_info.domainname)
1459 strncpy(pSesInfo->domainName,
1460 volume_info.domainname,MAX_USERNAME_SIZE);
1461 pSesInfo->linux_uid = volume_info.linux_uid;
1462 down(&pSesInfo->sesSem);
1463 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1464 up(&pSesInfo->sesSem);
1465 if(!rc)
1466 atomic_inc(&srvTcp->socketUseCount);
1467 } else
1468 if(volume_info.password)
1469 kfree(volume_info.password);
1470 }
1471
1472 /* search for existing tcon to this server share */
1473 if (!rc) {
1474 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1475 cifs_sb->rsize = volume_info.rsize;
1476 else
1477 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1478 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1479 cifs_sb->wsize = volume_info.wsize;
1480 else
1481 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1482 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1483 cifs_sb->rsize = PAGE_CACHE_SIZE;
1484 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1485 }
1486 cifs_sb->mnt_uid = volume_info.linux_uid;
1487 cifs_sb->mnt_gid = volume_info.linux_gid;
1488 cifs_sb->mnt_file_mode = volume_info.file_mode;
1489 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1490 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1491
1492 if(volume_info.noperm)
1493 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1494 if(volume_info.setuids)
1495 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1496 if(volume_info.server_ino)
1497 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001498 if(volume_info.remap)
1499 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 if(volume_info.no_xattr)
1501 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1502 if(volume_info.direct_io) {
1503 cERROR(1,("mounting share using direct i/o"));
1504 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1505 }
1506
1507 tcon =
1508 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1509 volume_info.username);
1510 if (tcon) {
1511 cFYI(1, ("Found match on UNC path "));
1512 /* we can have only one retry value for a connection
1513 to a share so for resources mounted more than once
1514 to the same server share the last value passed in
1515 for the retry flag is used */
1516 tcon->retry = volume_info.retry;
1517 } else {
1518 tcon = tconInfoAlloc();
1519 if (tcon == NULL)
1520 rc = -ENOMEM;
1521 else {
1522 /* check for null share name ie connect to dfs root */
1523
1524 /* BB check if this works for exactly length three strings */
1525 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1526 && (strchr(volume_info.UNC + 3, '/') ==
1527 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001528 rc = connect_to_dfs_path(xid, pSesInfo,
1529 "", cifs_sb->local_nls,
1530 cifs_sb->mnt_cifs_flags &
1531 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 if(volume_info.UNC)
1533 kfree(volume_info.UNC);
1534 FreeXid(xid);
1535 return -ENODEV;
1536 } else {
1537 rc = CIFSTCon(xid, pSesInfo,
1538 volume_info.UNC,
1539 tcon, cifs_sb->local_nls);
1540 cFYI(1, ("CIFS Tcon rc = %d", rc));
1541 }
1542 if (!rc) {
1543 atomic_inc(&pSesInfo->inUse);
1544 tcon->retry = volume_info.retry;
1545 }
1546 }
1547 }
1548 }
1549 if(pSesInfo) {
1550 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1551 sb->s_maxbytes = (u64) 1 << 63;
1552 } else
1553 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1554 }
1555
1556 sb->s_time_gran = 100;
1557
1558/* on error free sesinfo and tcon struct if needed */
1559 if (rc) {
1560 /* if session setup failed, use count is zero but
1561 we still need to free cifsd thread */
1562 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1563 spin_lock(&GlobalMid_Lock);
1564 srvTcp->tcpStatus = CifsExiting;
1565 spin_unlock(&GlobalMid_Lock);
1566 if(srvTcp->tsk)
1567 send_sig(SIGKILL,srvTcp->tsk,1);
1568 }
1569 /* If find_unc succeeded then rc == 0 so we can not end */
1570 if (tcon) /* up accidently freeing someone elses tcon struct */
1571 tconInfoFree(tcon);
1572 if (existingCifsSes == NULL) {
1573 if (pSesInfo) {
1574 if ((pSesInfo->server) &&
1575 (pSesInfo->status == CifsGood)) {
1576 int temp_rc;
1577 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1578 /* if the socketUseCount is now zero */
1579 if((temp_rc == -ESHUTDOWN) &&
1580 (pSesInfo->server->tsk))
1581 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1582 } else
1583 cFYI(1, ("No session or bad tcon"));
1584 sesInfoFree(pSesInfo);
1585 /* pSesInfo = NULL; */
1586 }
1587 }
1588 } else {
1589 atomic_inc(&tcon->useCount);
1590 cifs_sb->tcon = tcon;
1591 tcon->ses = pSesInfo;
1592
1593 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001594 CIFSSMBQFSDeviceInfo(xid, tcon);
1595 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001597 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 if(!volume_info.no_psx_acl) {
1599 if(CIFS_UNIX_POSIX_ACL_CAP &
1600 le64_to_cpu(tcon->fsUnixInfo.Capability))
1601 cFYI(1,("server negotiated posix acl support"));
1602 sb->s_flags |= MS_POSIXACL;
1603 }
1604 }
1605 }
1606 }
1607
1608 /* volume_info.password is freed above when existing session found
1609 (in which case it is not needed anymore) but when new sesion is created
1610 the password ptr is put in the new session structure (in which case the
1611 password will be freed at unmount time) */
1612 if(volume_info.UNC)
1613 kfree(volume_info.UNC);
1614 FreeXid(xid);
1615 return rc;
1616}
1617
1618static int
1619CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1620 char session_key[CIFS_SESSION_KEY_SIZE],
1621 const struct nls_table *nls_codepage)
1622{
1623 struct smb_hdr *smb_buffer;
1624 struct smb_hdr *smb_buffer_response;
1625 SESSION_SETUP_ANDX *pSMB;
1626 SESSION_SETUP_ANDX *pSMBr;
1627 char *bcc_ptr;
1628 char *user;
1629 char *domain;
1630 int rc = 0;
1631 int remaining_words = 0;
1632 int bytes_returned = 0;
1633 int len;
1634 __u32 capabilities;
1635 __u16 count;
1636
1637 cFYI(1, ("In sesssetup "));
1638 if(ses == NULL)
1639 return -EINVAL;
1640 user = ses->userName;
1641 domain = ses->domainName;
1642 smb_buffer = cifs_buf_get();
1643 if (smb_buffer == NULL) {
1644 return -ENOMEM;
1645 }
1646 smb_buffer_response = smb_buffer;
1647 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1648
1649 /* send SMBsessionSetup here */
1650 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1651 NULL /* no tCon exists yet */ , 13 /* wct */ );
1652
1653 pSMB->req_no_secext.AndXCommand = 0xFF;
1654 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1655 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1656
1657 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1658 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1659
1660 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1661 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1662 if (ses->capabilities & CAP_UNICODE) {
1663 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1664 capabilities |= CAP_UNICODE;
1665 }
1666 if (ses->capabilities & CAP_STATUS32) {
1667 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1668 capabilities |= CAP_STATUS32;
1669 }
1670 if (ses->capabilities & CAP_DFS) {
1671 smb_buffer->Flags2 |= SMBFLG2_DFS;
1672 capabilities |= CAP_DFS;
1673 }
1674 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1675
1676 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1677 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1678
1679 pSMB->req_no_secext.CaseSensitivePasswordLength =
1680 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1681 bcc_ptr = pByteArea(smb_buffer);
1682 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1683 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1684 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1685 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1686
1687 if (ses->capabilities & CAP_UNICODE) {
1688 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1689 *bcc_ptr = 0;
1690 bcc_ptr++;
1691 }
1692 if(user == NULL)
1693 bytes_returned = 0; /* skill null user */
1694 else
1695 bytes_returned =
1696 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1697 nls_codepage);
1698 /* convert number of 16 bit words to bytes */
1699 bcc_ptr += 2 * bytes_returned;
1700 bcc_ptr += 2; /* trailing null */
1701 if (domain == NULL)
1702 bytes_returned =
1703 cifs_strtoUCS((wchar_t *) bcc_ptr,
1704 "CIFS_LINUX_DOM", 32, nls_codepage);
1705 else
1706 bytes_returned =
1707 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1708 nls_codepage);
1709 bcc_ptr += 2 * bytes_returned;
1710 bcc_ptr += 2;
1711 bytes_returned =
1712 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1713 32, nls_codepage);
1714 bcc_ptr += 2 * bytes_returned;
1715 bytes_returned =
1716 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1717 32, nls_codepage);
1718 bcc_ptr += 2 * bytes_returned;
1719 bcc_ptr += 2;
1720 bytes_returned =
1721 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1722 64, nls_codepage);
1723 bcc_ptr += 2 * bytes_returned;
1724 bcc_ptr += 2;
1725 } else {
1726 if(user != NULL) {
1727 strncpy(bcc_ptr, user, 200);
1728 bcc_ptr += strnlen(user, 200);
1729 }
1730 *bcc_ptr = 0;
1731 bcc_ptr++;
1732 if (domain == NULL) {
1733 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1734 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1735 } else {
1736 strncpy(bcc_ptr, domain, 64);
1737 bcc_ptr += strnlen(domain, 64);
1738 *bcc_ptr = 0;
1739 bcc_ptr++;
1740 }
1741 strcpy(bcc_ptr, "Linux version ");
1742 bcc_ptr += strlen("Linux version ");
1743 strcpy(bcc_ptr, system_utsname.release);
1744 bcc_ptr += strlen(system_utsname.release) + 1;
1745 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1746 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1747 }
1748 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1749 smb_buffer->smb_buf_length += count;
1750 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1751
1752 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1753 &bytes_returned, 1);
1754 if (rc) {
1755/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1756 } else if ((smb_buffer_response->WordCount == 3)
1757 || (smb_buffer_response->WordCount == 4)) {
1758 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1759 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1760 if (action & GUEST_LOGIN)
1761 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1762 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1763 cFYI(1, ("UID = %d ", ses->Suid));
1764 /* response can have either 3 or 4 word count - Samba sends 3 */
1765 bcc_ptr = pByteArea(smb_buffer_response);
1766 if ((pSMBr->resp.hdr.WordCount == 3)
1767 || ((pSMBr->resp.hdr.WordCount == 4)
1768 && (blob_len < pSMBr->resp.ByteCount))) {
1769 if (pSMBr->resp.hdr.WordCount == 4)
1770 bcc_ptr += blob_len;
1771
1772 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1773 if ((long) (bcc_ptr) % 2) {
1774 remaining_words =
1775 (BCC(smb_buffer_response) - 1) /2;
1776 bcc_ptr++; /* Unicode strings must be word aligned */
1777 } else {
1778 remaining_words =
1779 BCC(smb_buffer_response) / 2;
1780 }
1781 len =
1782 UniStrnlen((wchar_t *) bcc_ptr,
1783 remaining_words - 1);
1784/* We look for obvious messed up bcc or strings in response so we do not go off
1785 the end since (at least) WIN2K and Windows XP have a major bug in not null
1786 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07001787 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
1788 if(ses->serverOS == NULL)
1789 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 cifs_strfromUCS_le(ses->serverOS,
1791 (wchar_t *)bcc_ptr, len,nls_codepage);
1792 bcc_ptr += 2 * (len + 1);
1793 remaining_words -= len + 1;
1794 ses->serverOS[2 * len] = 0;
1795 ses->serverOS[1 + (2 * len)] = 0;
1796 if (remaining_words > 0) {
1797 len = UniStrnlen((wchar_t *)bcc_ptr,
1798 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07001799 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
1800 if(ses->serverNOS == NULL)
1801 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 cifs_strfromUCS_le(ses->serverNOS,
1803 (wchar_t *)bcc_ptr,len,nls_codepage);
1804 bcc_ptr += 2 * (len + 1);
1805 ses->serverNOS[2 * len] = 0;
1806 ses->serverNOS[1 + (2 * len)] = 0;
1807 if(strncmp(ses->serverNOS,
1808 "NT LAN Manager 4",16) == 0) {
1809 cFYI(1,("NT4 server"));
1810 ses->flags |= CIFS_SES_NT4;
1811 }
1812 remaining_words -= len + 1;
1813 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07001814 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1816 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07001817 kcalloc(1, 2*(len+1),GFP_KERNEL);
1818 if(ses->serverDomain == NULL)
1819 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 cifs_strfromUCS_le(ses->serverDomain,
1821 (wchar_t *)bcc_ptr,len,nls_codepage);
1822 bcc_ptr += 2 * (len + 1);
1823 ses->serverDomain[2*len] = 0;
1824 ses->serverDomain[1+(2*len)] = 0;
1825 } /* else no more room so create dummy domain string */
1826 else
Steve French433dc242005-04-28 22:41:08 -07001827 ses->serverDomain =
1828 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07001830 /* if these kcallocs fail not much we
1831 can do, but better to not fail the
1832 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07001834 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07001836 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 }
1838 } else { /* ASCII */
1839 len = strnlen(bcc_ptr, 1024);
1840 if (((long) bcc_ptr + len) - (long)
1841 pByteArea(smb_buffer_response)
1842 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07001843 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
1844 if(ses->serverOS == NULL)
1845 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 strncpy(ses->serverOS,bcc_ptr, len);
1847
1848 bcc_ptr += len;
1849 bcc_ptr[0] = 0; /* null terminate the string */
1850 bcc_ptr++;
1851
1852 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07001853 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
1854 if(ses->serverNOS == NULL)
1855 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 strncpy(ses->serverNOS, bcc_ptr, len);
1857 bcc_ptr += len;
1858 bcc_ptr[0] = 0;
1859 bcc_ptr++;
1860
1861 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07001862 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
1863 if(ses->serverDomain == NULL)
1864 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 strncpy(ses->serverDomain, bcc_ptr, len);
1866 bcc_ptr += len;
1867 bcc_ptr[0] = 0;
1868 bcc_ptr++;
1869 } else
1870 cFYI(1,
1871 ("Variable field of length %d extends beyond end of smb ",
1872 len));
1873 }
1874 } else {
1875 cERROR(1,
1876 (" Security Blob Length extends beyond end of SMB"));
1877 }
1878 } else {
1879 cERROR(1,
1880 (" Invalid Word count %d: ",
1881 smb_buffer_response->WordCount));
1882 rc = -EIO;
1883 }
Steve French433dc242005-04-28 22:41:08 -07001884sesssetup_nomem: /* do not return an error on nomem for the info strings,
1885 since that could make reconnection harder, and
1886 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 if (smb_buffer)
1888 cifs_buf_release(smb_buffer);
1889
1890 return rc;
1891}
1892
1893static int
1894CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1895 char *SecurityBlob,int SecurityBlobLength,
1896 const struct nls_table *nls_codepage)
1897{
1898 struct smb_hdr *smb_buffer;
1899 struct smb_hdr *smb_buffer_response;
1900 SESSION_SETUP_ANDX *pSMB;
1901 SESSION_SETUP_ANDX *pSMBr;
1902 char *bcc_ptr;
1903 char *user;
1904 char *domain;
1905 int rc = 0;
1906 int remaining_words = 0;
1907 int bytes_returned = 0;
1908 int len;
1909 __u32 capabilities;
1910 __u16 count;
1911
1912 cFYI(1, ("In spnego sesssetup "));
1913 if(ses == NULL)
1914 return -EINVAL;
1915 user = ses->userName;
1916 domain = ses->domainName;
1917
1918 smb_buffer = cifs_buf_get();
1919 if (smb_buffer == NULL) {
1920 return -ENOMEM;
1921 }
1922 smb_buffer_response = smb_buffer;
1923 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1924
1925 /* send SMBsessionSetup here */
1926 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1927 NULL /* no tCon exists yet */ , 12 /* wct */ );
1928 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1929 pSMB->req.AndXCommand = 0xFF;
1930 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1931 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1932
1933 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1934 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1935
1936 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1937 CAP_EXTENDED_SECURITY;
1938 if (ses->capabilities & CAP_UNICODE) {
1939 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1940 capabilities |= CAP_UNICODE;
1941 }
1942 if (ses->capabilities & CAP_STATUS32) {
1943 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1944 capabilities |= CAP_STATUS32;
1945 }
1946 if (ses->capabilities & CAP_DFS) {
1947 smb_buffer->Flags2 |= SMBFLG2_DFS;
1948 capabilities |= CAP_DFS;
1949 }
1950 pSMB->req.Capabilities = cpu_to_le32(capabilities);
1951
1952 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
1953 bcc_ptr = pByteArea(smb_buffer);
1954 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
1955 bcc_ptr += SecurityBlobLength;
1956
1957 if (ses->capabilities & CAP_UNICODE) {
1958 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
1959 *bcc_ptr = 0;
1960 bcc_ptr++;
1961 }
1962 bytes_returned =
1963 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
1964 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
1965 bcc_ptr += 2; /* trailing null */
1966 if (domain == NULL)
1967 bytes_returned =
1968 cifs_strtoUCS((wchar_t *) bcc_ptr,
1969 "CIFS_LINUX_DOM", 32, nls_codepage);
1970 else
1971 bytes_returned =
1972 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1973 nls_codepage);
1974 bcc_ptr += 2 * bytes_returned;
1975 bcc_ptr += 2;
1976 bytes_returned =
1977 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1978 32, nls_codepage);
1979 bcc_ptr += 2 * bytes_returned;
1980 bytes_returned =
1981 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
1982 nls_codepage);
1983 bcc_ptr += 2 * bytes_returned;
1984 bcc_ptr += 2;
1985 bytes_returned =
1986 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1987 64, nls_codepage);
1988 bcc_ptr += 2 * bytes_returned;
1989 bcc_ptr += 2;
1990 } else {
1991 strncpy(bcc_ptr, user, 200);
1992 bcc_ptr += strnlen(user, 200);
1993 *bcc_ptr = 0;
1994 bcc_ptr++;
1995 if (domain == NULL) {
1996 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1997 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1998 } else {
1999 strncpy(bcc_ptr, domain, 64);
2000 bcc_ptr += strnlen(domain, 64);
2001 *bcc_ptr = 0;
2002 bcc_ptr++;
2003 }
2004 strcpy(bcc_ptr, "Linux version ");
2005 bcc_ptr += strlen("Linux version ");
2006 strcpy(bcc_ptr, system_utsname.release);
2007 bcc_ptr += strlen(system_utsname.release) + 1;
2008 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2009 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2010 }
2011 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2012 smb_buffer->smb_buf_length += count;
2013 pSMB->req.ByteCount = cpu_to_le16(count);
2014
2015 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2016 &bytes_returned, 1);
2017 if (rc) {
2018/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2019 } else if ((smb_buffer_response->WordCount == 3)
2020 || (smb_buffer_response->WordCount == 4)) {
2021 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2022 __u16 blob_len =
2023 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2024 if (action & GUEST_LOGIN)
2025 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2026 if (ses) {
2027 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2028 cFYI(1, ("UID = %d ", ses->Suid));
2029 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2030
2031 /* BB Fix below to make endian neutral !! */
2032
2033 if ((pSMBr->resp.hdr.WordCount == 3)
2034 || ((pSMBr->resp.hdr.WordCount == 4)
2035 && (blob_len <
2036 pSMBr->resp.ByteCount))) {
2037 if (pSMBr->resp.hdr.WordCount == 4) {
2038 bcc_ptr +=
2039 blob_len;
2040 cFYI(1,
2041 ("Security Blob Length %d ",
2042 blob_len));
2043 }
2044
2045 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2046 if ((long) (bcc_ptr) % 2) {
2047 remaining_words =
2048 (BCC(smb_buffer_response)
2049 - 1) / 2;
2050 bcc_ptr++; /* Unicode strings must be word aligned */
2051 } else {
2052 remaining_words =
2053 BCC
2054 (smb_buffer_response) / 2;
2055 }
2056 len =
2057 UniStrnlen((wchar_t *) bcc_ptr,
2058 remaining_words - 1);
2059/* We look for obvious messed up bcc or strings in response so we do not go off
2060 the end since (at least) WIN2K and Windows XP have a major bug in not null
2061 terminating last Unicode string in response */
2062 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002063 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 cifs_strfromUCS_le(ses->serverOS,
2065 (wchar_t *)
2066 bcc_ptr, len,
2067 nls_codepage);
2068 bcc_ptr += 2 * (len + 1);
2069 remaining_words -= len + 1;
2070 ses->serverOS[2 * len] = 0;
2071 ses->serverOS[1 + (2 * len)] = 0;
2072 if (remaining_words > 0) {
2073 len = UniStrnlen((wchar_t *)bcc_ptr,
2074 remaining_words
2075 - 1);
2076 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002077 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 GFP_KERNEL);
2079 cifs_strfromUCS_le(ses->serverNOS,
2080 (wchar_t *)bcc_ptr,
2081 len,
2082 nls_codepage);
2083 bcc_ptr += 2 * (len + 1);
2084 ses->serverNOS[2 * len] = 0;
2085 ses->serverNOS[1 + (2 * len)] = 0;
2086 remaining_words -= len + 1;
2087 if (remaining_words > 0) {
2088 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2089 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002090 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 cifs_strfromUCS_le(ses->serverDomain,
2092 (wchar_t *)bcc_ptr,
2093 len,
2094 nls_codepage);
2095 bcc_ptr += 2*(len+1);
2096 ses->serverDomain[2*len] = 0;
2097 ses->serverDomain[1+(2*len)] = 0;
2098 } /* else no more room so create dummy domain string */
2099 else
2100 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002101 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002103 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2104 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 }
2106 } else { /* ASCII */
2107
2108 len = strnlen(bcc_ptr, 1024);
2109 if (((long) bcc_ptr + len) - (long)
2110 pByteArea(smb_buffer_response)
2111 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002112 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 strncpy(ses->serverOS, bcc_ptr, len);
2114
2115 bcc_ptr += len;
2116 bcc_ptr[0] = 0; /* null terminate the string */
2117 bcc_ptr++;
2118
2119 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002120 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 strncpy(ses->serverNOS, bcc_ptr, len);
2122 bcc_ptr += len;
2123 bcc_ptr[0] = 0;
2124 bcc_ptr++;
2125
2126 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002127 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 strncpy(ses->serverDomain, bcc_ptr, len);
2129 bcc_ptr += len;
2130 bcc_ptr[0] = 0;
2131 bcc_ptr++;
2132 } else
2133 cFYI(1,
2134 ("Variable field of length %d extends beyond end of smb ",
2135 len));
2136 }
2137 } else {
2138 cERROR(1,
2139 (" Security Blob Length extends beyond end of SMB"));
2140 }
2141 } else {
2142 cERROR(1, ("No session structure passed in."));
2143 }
2144 } else {
2145 cERROR(1,
2146 (" Invalid Word count %d: ",
2147 smb_buffer_response->WordCount));
2148 rc = -EIO;
2149 }
2150
2151 if (smb_buffer)
2152 cifs_buf_release(smb_buffer);
2153
2154 return rc;
2155}
2156
2157static int
2158CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2159 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2160 const struct nls_table *nls_codepage)
2161{
2162 struct smb_hdr *smb_buffer;
2163 struct smb_hdr *smb_buffer_response;
2164 SESSION_SETUP_ANDX *pSMB;
2165 SESSION_SETUP_ANDX *pSMBr;
2166 char *bcc_ptr;
2167 char *domain;
2168 int rc = 0;
2169 int remaining_words = 0;
2170 int bytes_returned = 0;
2171 int len;
2172 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2173 PNEGOTIATE_MESSAGE SecurityBlob;
2174 PCHALLENGE_MESSAGE SecurityBlob2;
2175 __u32 negotiate_flags, capabilities;
2176 __u16 count;
2177
2178 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2179 if(ses == NULL)
2180 return -EINVAL;
2181 domain = ses->domainName;
2182 *pNTLMv2_flag = FALSE;
2183 smb_buffer = cifs_buf_get();
2184 if (smb_buffer == NULL) {
2185 return -ENOMEM;
2186 }
2187 smb_buffer_response = smb_buffer;
2188 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2189 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2190
2191 /* send SMBsessionSetup here */
2192 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2193 NULL /* no tCon exists yet */ , 12 /* wct */ );
2194 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2195 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2196
2197 pSMB->req.AndXCommand = 0xFF;
2198 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2199 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2200
2201 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2202 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2203
2204 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2205 CAP_EXTENDED_SECURITY;
2206 if (ses->capabilities & CAP_UNICODE) {
2207 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2208 capabilities |= CAP_UNICODE;
2209 }
2210 if (ses->capabilities & CAP_STATUS32) {
2211 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2212 capabilities |= CAP_STATUS32;
2213 }
2214 if (ses->capabilities & CAP_DFS) {
2215 smb_buffer->Flags2 |= SMBFLG2_DFS;
2216 capabilities |= CAP_DFS;
2217 }
2218 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2219
2220 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2221 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2222 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2223 SecurityBlob->MessageType = NtLmNegotiate;
2224 negotiate_flags =
2225 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2226 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2227 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2228 if(sign_CIFS_PDUs)
2229 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2230 if(ntlmv2_support)
2231 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2232 /* setup pointers to domain name and workstation name */
2233 bcc_ptr += SecurityBlobLength;
2234
2235 SecurityBlob->WorkstationName.Buffer = 0;
2236 SecurityBlob->WorkstationName.Length = 0;
2237 SecurityBlob->WorkstationName.MaximumLength = 0;
2238
2239 if (domain == NULL) {
2240 SecurityBlob->DomainName.Buffer = 0;
2241 SecurityBlob->DomainName.Length = 0;
2242 SecurityBlob->DomainName.MaximumLength = 0;
2243 } else {
2244 __u16 len;
2245 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2246 strncpy(bcc_ptr, domain, 63);
2247 len = strnlen(domain, 64);
2248 SecurityBlob->DomainName.MaximumLength =
2249 cpu_to_le16(len);
2250 SecurityBlob->DomainName.Buffer =
2251 cpu_to_le32((long) &SecurityBlob->
2252 DomainString -
2253 (long) &SecurityBlob->Signature);
2254 bcc_ptr += len;
2255 SecurityBlobLength += len;
2256 SecurityBlob->DomainName.Length =
2257 cpu_to_le16(len);
2258 }
2259 if (ses->capabilities & CAP_UNICODE) {
2260 if ((long) bcc_ptr % 2) {
2261 *bcc_ptr = 0;
2262 bcc_ptr++;
2263 }
2264
2265 bytes_returned =
2266 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2267 32, nls_codepage);
2268 bcc_ptr += 2 * bytes_returned;
2269 bytes_returned =
2270 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2271 nls_codepage);
2272 bcc_ptr += 2 * bytes_returned;
2273 bcc_ptr += 2; /* null terminate Linux version */
2274 bytes_returned =
2275 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2276 64, nls_codepage);
2277 bcc_ptr += 2 * bytes_returned;
2278 *(bcc_ptr + 1) = 0;
2279 *(bcc_ptr + 2) = 0;
2280 bcc_ptr += 2; /* null terminate network opsys string */
2281 *(bcc_ptr + 1) = 0;
2282 *(bcc_ptr + 2) = 0;
2283 bcc_ptr += 2; /* null domain */
2284 } else { /* ASCII */
2285 strcpy(bcc_ptr, "Linux version ");
2286 bcc_ptr += strlen("Linux version ");
2287 strcpy(bcc_ptr, system_utsname.release);
2288 bcc_ptr += strlen(system_utsname.release) + 1;
2289 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2290 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2291 bcc_ptr++; /* empty domain field */
2292 *bcc_ptr = 0;
2293 }
2294 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2295 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2296 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2297 smb_buffer->smb_buf_length += count;
2298 pSMB->req.ByteCount = cpu_to_le16(count);
2299
2300 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2301 &bytes_returned, 1);
2302
2303 if (smb_buffer_response->Status.CifsError ==
2304 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2305 rc = 0;
2306
2307 if (rc) {
2308/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2309 } else if ((smb_buffer_response->WordCount == 3)
2310 || (smb_buffer_response->WordCount == 4)) {
2311 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2312 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2313
2314 if (action & GUEST_LOGIN)
2315 cFYI(1, (" Guest login"));
2316 /* Do we want to set anything in SesInfo struct when guest login? */
2317
2318 bcc_ptr = pByteArea(smb_buffer_response);
2319 /* response can have either 3 or 4 word count - Samba sends 3 */
2320
2321 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2322 if (SecurityBlob2->MessageType != NtLmChallenge) {
2323 cFYI(1,
2324 ("Unexpected NTLMSSP message type received %d",
2325 SecurityBlob2->MessageType));
2326 } else if (ses) {
2327 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2328 cFYI(1, ("UID = %d ", ses->Suid));
2329 if ((pSMBr->resp.hdr.WordCount == 3)
2330 || ((pSMBr->resp.hdr.WordCount == 4)
2331 && (blob_len <
2332 pSMBr->resp.ByteCount))) {
2333
2334 if (pSMBr->resp.hdr.WordCount == 4) {
2335 bcc_ptr += blob_len;
2336 cFYI(1,
2337 ("Security Blob Length %d ",
2338 blob_len));
2339 }
2340
2341 cFYI(1, ("NTLMSSP Challenge rcvd "));
2342
2343 memcpy(ses->server->cryptKey,
2344 SecurityBlob2->Challenge,
2345 CIFS_CRYPTO_KEY_SIZE);
2346 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2347 *pNTLMv2_flag = TRUE;
2348
2349 if((SecurityBlob2->NegotiateFlags &
2350 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2351 || (sign_CIFS_PDUs > 1))
2352 ses->server->secMode |=
2353 SECMODE_SIGN_REQUIRED;
2354 if ((SecurityBlob2->NegotiateFlags &
2355 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2356 ses->server->secMode |=
2357 SECMODE_SIGN_ENABLED;
2358
2359 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2360 if ((long) (bcc_ptr) % 2) {
2361 remaining_words =
2362 (BCC(smb_buffer_response)
2363 - 1) / 2;
2364 bcc_ptr++; /* Unicode strings must be word aligned */
2365 } else {
2366 remaining_words =
2367 BCC
2368 (smb_buffer_response) / 2;
2369 }
2370 len =
2371 UniStrnlen((wchar_t *) bcc_ptr,
2372 remaining_words - 1);
2373/* We look for obvious messed up bcc or strings in response so we do not go off
2374 the end since (at least) WIN2K and Windows XP have a major bug in not null
2375 terminating last Unicode string in response */
2376 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002377 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 cifs_strfromUCS_le(ses->serverOS,
2379 (wchar_t *)
2380 bcc_ptr, len,
2381 nls_codepage);
2382 bcc_ptr += 2 * (len + 1);
2383 remaining_words -= len + 1;
2384 ses->serverOS[2 * len] = 0;
2385 ses->serverOS[1 + (2 * len)] = 0;
2386 if (remaining_words > 0) {
2387 len = UniStrnlen((wchar_t *)
2388 bcc_ptr,
2389 remaining_words
2390 - 1);
2391 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002392 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 GFP_KERNEL);
2394 cifs_strfromUCS_le(ses->
2395 serverNOS,
2396 (wchar_t *)
2397 bcc_ptr,
2398 len,
2399 nls_codepage);
2400 bcc_ptr += 2 * (len + 1);
2401 ses->serverNOS[2 * len] = 0;
2402 ses->serverNOS[1 +
2403 (2 * len)] = 0;
2404 remaining_words -= len + 1;
2405 if (remaining_words > 0) {
2406 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2407 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2408 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002409 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 (len +
2411 1),
2412 GFP_KERNEL);
2413 cifs_strfromUCS_le
2414 (ses->
2415 serverDomain,
2416 (wchar_t *)
2417 bcc_ptr, len,
2418 nls_codepage);
2419 bcc_ptr +=
2420 2 * (len + 1);
2421 ses->
2422 serverDomain[2
2423 * len]
2424 = 0;
2425 ses->
2426 serverDomain[1
2427 +
2428 (2
2429 *
2430 len)]
2431 = 0;
2432 } /* else no more room so create dummy domain string */
2433 else
2434 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002435 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 GFP_KERNEL);
2437 } else { /* no room so create dummy domain and NOS string */
2438 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002439 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002441 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 }
2443 } else { /* ASCII */
2444 len = strnlen(bcc_ptr, 1024);
2445 if (((long) bcc_ptr + len) - (long)
2446 pByteArea(smb_buffer_response)
2447 <= BCC(smb_buffer_response)) {
2448 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002449 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 GFP_KERNEL);
2451 strncpy(ses->serverOS,
2452 bcc_ptr, len);
2453
2454 bcc_ptr += len;
2455 bcc_ptr[0] = 0; /* null terminate string */
2456 bcc_ptr++;
2457
2458 len = strnlen(bcc_ptr, 1024);
2459 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002460 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 GFP_KERNEL);
2462 strncpy(ses->serverNOS, bcc_ptr, len);
2463 bcc_ptr += len;
2464 bcc_ptr[0] = 0;
2465 bcc_ptr++;
2466
2467 len = strnlen(bcc_ptr, 1024);
2468 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002469 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 GFP_KERNEL);
2471 strncpy(ses->serverDomain, bcc_ptr, len);
2472 bcc_ptr += len;
2473 bcc_ptr[0] = 0;
2474 bcc_ptr++;
2475 } else
2476 cFYI(1,
2477 ("Variable field of length %d extends beyond end of smb ",
2478 len));
2479 }
2480 } else {
2481 cERROR(1,
2482 (" Security Blob Length extends beyond end of SMB"));
2483 }
2484 } else {
2485 cERROR(1, ("No session structure passed in."));
2486 }
2487 } else {
2488 cERROR(1,
2489 (" Invalid Word count %d: ",
2490 smb_buffer_response->WordCount));
2491 rc = -EIO;
2492 }
2493
2494 if (smb_buffer)
2495 cifs_buf_release(smb_buffer);
2496
2497 return rc;
2498}
2499static int
2500CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2501 char *ntlm_session_key, int ntlmv2_flag,
2502 const struct nls_table *nls_codepage)
2503{
2504 struct smb_hdr *smb_buffer;
2505 struct smb_hdr *smb_buffer_response;
2506 SESSION_SETUP_ANDX *pSMB;
2507 SESSION_SETUP_ANDX *pSMBr;
2508 char *bcc_ptr;
2509 char *user;
2510 char *domain;
2511 int rc = 0;
2512 int remaining_words = 0;
2513 int bytes_returned = 0;
2514 int len;
2515 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2516 PAUTHENTICATE_MESSAGE SecurityBlob;
2517 __u32 negotiate_flags, capabilities;
2518 __u16 count;
2519
2520 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2521 if(ses == NULL)
2522 return -EINVAL;
2523 user = ses->userName;
2524 domain = ses->domainName;
2525 smb_buffer = cifs_buf_get();
2526 if (smb_buffer == NULL) {
2527 return -ENOMEM;
2528 }
2529 smb_buffer_response = smb_buffer;
2530 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2531 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2532
2533 /* send SMBsessionSetup here */
2534 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2535 NULL /* no tCon exists yet */ , 12 /* wct */ );
2536 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2537 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2538 pSMB->req.AndXCommand = 0xFF;
2539 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2540 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2541
2542 pSMB->req.hdr.Uid = ses->Suid;
2543
2544 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2545 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2546
2547 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2548 CAP_EXTENDED_SECURITY;
2549 if (ses->capabilities & CAP_UNICODE) {
2550 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2551 capabilities |= CAP_UNICODE;
2552 }
2553 if (ses->capabilities & CAP_STATUS32) {
2554 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2555 capabilities |= CAP_STATUS32;
2556 }
2557 if (ses->capabilities & CAP_DFS) {
2558 smb_buffer->Flags2 |= SMBFLG2_DFS;
2559 capabilities |= CAP_DFS;
2560 }
2561 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2562
2563 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2564 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2565 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2566 SecurityBlob->MessageType = NtLmAuthenticate;
2567 bcc_ptr += SecurityBlobLength;
2568 negotiate_flags =
2569 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2570 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2571 0x80000000 | NTLMSSP_NEGOTIATE_128;
2572 if(sign_CIFS_PDUs)
2573 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2574 if(ntlmv2_flag)
2575 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2576
2577/* setup pointers to domain name and workstation name */
2578
2579 SecurityBlob->WorkstationName.Buffer = 0;
2580 SecurityBlob->WorkstationName.Length = 0;
2581 SecurityBlob->WorkstationName.MaximumLength = 0;
2582 SecurityBlob->SessionKey.Length = 0;
2583 SecurityBlob->SessionKey.MaximumLength = 0;
2584 SecurityBlob->SessionKey.Buffer = 0;
2585
2586 SecurityBlob->LmChallengeResponse.Length = 0;
2587 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2588 SecurityBlob->LmChallengeResponse.Buffer = 0;
2589
2590 SecurityBlob->NtChallengeResponse.Length =
2591 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2592 SecurityBlob->NtChallengeResponse.MaximumLength =
2593 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2594 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2595 SecurityBlob->NtChallengeResponse.Buffer =
2596 cpu_to_le32(SecurityBlobLength);
2597 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2598 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2599
2600 if (ses->capabilities & CAP_UNICODE) {
2601 if (domain == NULL) {
2602 SecurityBlob->DomainName.Buffer = 0;
2603 SecurityBlob->DomainName.Length = 0;
2604 SecurityBlob->DomainName.MaximumLength = 0;
2605 } else {
2606 __u16 len =
2607 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2608 nls_codepage);
2609 len *= 2;
2610 SecurityBlob->DomainName.MaximumLength =
2611 cpu_to_le16(len);
2612 SecurityBlob->DomainName.Buffer =
2613 cpu_to_le32(SecurityBlobLength);
2614 bcc_ptr += len;
2615 SecurityBlobLength += len;
2616 SecurityBlob->DomainName.Length =
2617 cpu_to_le16(len);
2618 }
2619 if (user == NULL) {
2620 SecurityBlob->UserName.Buffer = 0;
2621 SecurityBlob->UserName.Length = 0;
2622 SecurityBlob->UserName.MaximumLength = 0;
2623 } else {
2624 __u16 len =
2625 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2626 nls_codepage);
2627 len *= 2;
2628 SecurityBlob->UserName.MaximumLength =
2629 cpu_to_le16(len);
2630 SecurityBlob->UserName.Buffer =
2631 cpu_to_le32(SecurityBlobLength);
2632 bcc_ptr += len;
2633 SecurityBlobLength += len;
2634 SecurityBlob->UserName.Length =
2635 cpu_to_le16(len);
2636 }
2637
2638 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2639 SecurityBlob->WorkstationName.Length *= 2;
2640 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2641 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2642 bcc_ptr += SecurityBlob->WorkstationName.Length;
2643 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2644 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2645
2646 if ((long) bcc_ptr % 2) {
2647 *bcc_ptr = 0;
2648 bcc_ptr++;
2649 }
2650 bytes_returned =
2651 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2652 32, nls_codepage);
2653 bcc_ptr += 2 * bytes_returned;
2654 bytes_returned =
2655 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2656 nls_codepage);
2657 bcc_ptr += 2 * bytes_returned;
2658 bcc_ptr += 2; /* null term version string */
2659 bytes_returned =
2660 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2661 64, nls_codepage);
2662 bcc_ptr += 2 * bytes_returned;
2663 *(bcc_ptr + 1) = 0;
2664 *(bcc_ptr + 2) = 0;
2665 bcc_ptr += 2; /* null terminate network opsys string */
2666 *(bcc_ptr + 1) = 0;
2667 *(bcc_ptr + 2) = 0;
2668 bcc_ptr += 2; /* null domain */
2669 } else { /* ASCII */
2670 if (domain == NULL) {
2671 SecurityBlob->DomainName.Buffer = 0;
2672 SecurityBlob->DomainName.Length = 0;
2673 SecurityBlob->DomainName.MaximumLength = 0;
2674 } else {
2675 __u16 len;
2676 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2677 strncpy(bcc_ptr, domain, 63);
2678 len = strnlen(domain, 64);
2679 SecurityBlob->DomainName.MaximumLength =
2680 cpu_to_le16(len);
2681 SecurityBlob->DomainName.Buffer =
2682 cpu_to_le32(SecurityBlobLength);
2683 bcc_ptr += len;
2684 SecurityBlobLength += len;
2685 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2686 }
2687 if (user == NULL) {
2688 SecurityBlob->UserName.Buffer = 0;
2689 SecurityBlob->UserName.Length = 0;
2690 SecurityBlob->UserName.MaximumLength = 0;
2691 } else {
2692 __u16 len;
2693 strncpy(bcc_ptr, user, 63);
2694 len = strnlen(user, 64);
2695 SecurityBlob->UserName.MaximumLength =
2696 cpu_to_le16(len);
2697 SecurityBlob->UserName.Buffer =
2698 cpu_to_le32(SecurityBlobLength);
2699 bcc_ptr += len;
2700 SecurityBlobLength += len;
2701 SecurityBlob->UserName.Length = cpu_to_le16(len);
2702 }
2703 /* BB fill in our workstation name if known BB */
2704
2705 strcpy(bcc_ptr, "Linux version ");
2706 bcc_ptr += strlen("Linux version ");
2707 strcpy(bcc_ptr, system_utsname.release);
2708 bcc_ptr += strlen(system_utsname.release) + 1;
2709 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2710 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2711 bcc_ptr++; /* null domain */
2712 *bcc_ptr = 0;
2713 }
2714 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2715 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2716 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2717 smb_buffer->smb_buf_length += count;
2718 pSMB->req.ByteCount = cpu_to_le16(count);
2719
2720 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2721 &bytes_returned, 1);
2722 if (rc) {
2723/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2724 } else if ((smb_buffer_response->WordCount == 3)
2725 || (smb_buffer_response->WordCount == 4)) {
2726 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2727 __u16 blob_len =
2728 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2729 if (action & GUEST_LOGIN)
2730 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2731/* if(SecurityBlob2->MessageType != NtLm??){
2732 cFYI("Unexpected message type on auth response is %d "));
2733 } */
2734 if (ses) {
2735 cFYI(1,
2736 ("Does UID on challenge %d match auth response UID %d ",
2737 ses->Suid, smb_buffer_response->Uid));
2738 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2739 bcc_ptr = pByteArea(smb_buffer_response);
2740 /* response can have either 3 or 4 word count - Samba sends 3 */
2741 if ((pSMBr->resp.hdr.WordCount == 3)
2742 || ((pSMBr->resp.hdr.WordCount == 4)
2743 && (blob_len <
2744 pSMBr->resp.ByteCount))) {
2745 if (pSMBr->resp.hdr.WordCount == 4) {
2746 bcc_ptr +=
2747 blob_len;
2748 cFYI(1,
2749 ("Security Blob Length %d ",
2750 blob_len));
2751 }
2752
2753 cFYI(1,
2754 ("NTLMSSP response to Authenticate "));
2755
2756 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2757 if ((long) (bcc_ptr) % 2) {
2758 remaining_words =
2759 (BCC(smb_buffer_response)
2760 - 1) / 2;
2761 bcc_ptr++; /* Unicode strings must be word aligned */
2762 } else {
2763 remaining_words = BCC(smb_buffer_response) / 2;
2764 }
2765 len =
2766 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2767/* We look for obvious messed up bcc or strings in response so we do not go off
2768 the end since (at least) WIN2K and Windows XP have a major bug in not null
2769 terminating last Unicode string in response */
2770 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002771 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 cifs_strfromUCS_le(ses->serverOS,
2773 (wchar_t *)
2774 bcc_ptr, len,
2775 nls_codepage);
2776 bcc_ptr += 2 * (len + 1);
2777 remaining_words -= len + 1;
2778 ses->serverOS[2 * len] = 0;
2779 ses->serverOS[1 + (2 * len)] = 0;
2780 if (remaining_words > 0) {
2781 len = UniStrnlen((wchar_t *)
2782 bcc_ptr,
2783 remaining_words
2784 - 1);
2785 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002786 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 GFP_KERNEL);
2788 cifs_strfromUCS_le(ses->
2789 serverNOS,
2790 (wchar_t *)
2791 bcc_ptr,
2792 len,
2793 nls_codepage);
2794 bcc_ptr += 2 * (len + 1);
2795 ses->serverNOS[2 * len] = 0;
2796 ses->serverNOS[1+(2*len)] = 0;
2797 remaining_words -= len + 1;
2798 if (remaining_words > 0) {
2799 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2800 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2801 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002802 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 (len +
2804 1),
2805 GFP_KERNEL);
2806 cifs_strfromUCS_le
2807 (ses->
2808 serverDomain,
2809 (wchar_t *)
2810 bcc_ptr, len,
2811 nls_codepage);
2812 bcc_ptr +=
2813 2 * (len + 1);
2814 ses->
2815 serverDomain[2
2816 * len]
2817 = 0;
2818 ses->
2819 serverDomain[1
2820 +
2821 (2
2822 *
2823 len)]
2824 = 0;
2825 } /* else no more room so create dummy domain string */
2826 else
Steve French433dc242005-04-28 22:41:08 -07002827 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002829 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2830 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 }
2832 } else { /* ASCII */
2833 len = strnlen(bcc_ptr, 1024);
2834 if (((long) bcc_ptr + len) -
2835 (long) pByteArea(smb_buffer_response)
2836 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002837 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 strncpy(ses->serverOS,bcc_ptr, len);
2839
2840 bcc_ptr += len;
2841 bcc_ptr[0] = 0; /* null terminate the string */
2842 bcc_ptr++;
2843
2844 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002845 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 strncpy(ses->serverNOS, bcc_ptr, len);
2847 bcc_ptr += len;
2848 bcc_ptr[0] = 0;
2849 bcc_ptr++;
2850
2851 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002852 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 strncpy(ses->serverDomain, bcc_ptr, len);
2854 bcc_ptr += len;
2855 bcc_ptr[0] = 0;
2856 bcc_ptr++;
2857 } else
2858 cFYI(1,
2859 ("Variable field of length %d extends beyond end of smb ",
2860 len));
2861 }
2862 } else {
2863 cERROR(1,
2864 (" Security Blob Length extends beyond end of SMB"));
2865 }
2866 } else {
2867 cERROR(1, ("No session structure passed in."));
2868 }
2869 } else {
2870 cERROR(1,
2871 (" Invalid Word count %d: ",
2872 smb_buffer_response->WordCount));
2873 rc = -EIO;
2874 }
2875
2876 if (smb_buffer)
2877 cifs_buf_release(smb_buffer);
2878
2879 return rc;
2880}
2881
2882int
2883CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2884 const char *tree, struct cifsTconInfo *tcon,
2885 const struct nls_table *nls_codepage)
2886{
2887 struct smb_hdr *smb_buffer;
2888 struct smb_hdr *smb_buffer_response;
2889 TCONX_REQ *pSMB;
2890 TCONX_RSP *pSMBr;
2891 unsigned char *bcc_ptr;
2892 int rc = 0;
2893 int length;
2894 __u16 count;
2895
2896 if (ses == NULL)
2897 return -EIO;
2898
2899 smb_buffer = cifs_buf_get();
2900 if (smb_buffer == NULL) {
2901 return -ENOMEM;
2902 }
2903 smb_buffer_response = smb_buffer;
2904
2905 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2906 NULL /*no tid */ , 4 /*wct */ );
2907 smb_buffer->Uid = ses->Suid;
2908 pSMB = (TCONX_REQ *) smb_buffer;
2909 pSMBr = (TCONX_RSP *) smb_buffer_response;
2910
2911 pSMB->AndXCommand = 0xFF;
2912 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
2913 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
2914 bcc_ptr = &pSMB->Password[0];
2915 bcc_ptr++; /* skip password */
2916
2917 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2918 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2919
2920 if (ses->capabilities & CAP_STATUS32) {
2921 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2922 }
2923 if (ses->capabilities & CAP_DFS) {
2924 smb_buffer->Flags2 |= SMBFLG2_DFS;
2925 }
2926 if (ses->capabilities & CAP_UNICODE) {
2927 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2928 length =
2929 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
2930 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
2931 bcc_ptr += 2; /* skip trailing null */
2932 } else { /* ASCII */
2933
2934 strcpy(bcc_ptr, tree);
2935 bcc_ptr += strlen(tree) + 1;
2936 }
2937 strcpy(bcc_ptr, "?????");
2938 bcc_ptr += strlen("?????");
2939 bcc_ptr += 1;
2940 count = bcc_ptr - &pSMB->Password[0];
2941 pSMB->hdr.smb_buf_length += count;
2942 pSMB->ByteCount = cpu_to_le16(count);
2943
2944 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
2945
2946 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
2947 /* above now done in SendReceive */
2948 if ((rc == 0) && (tcon != NULL)) {
2949 tcon->tidStatus = CifsGood;
2950 tcon->tid = smb_buffer_response->Tid;
2951 bcc_ptr = pByteArea(smb_buffer_response);
2952 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
2953 /* skip service field (NB: this field is always ASCII) */
2954 bcc_ptr += length + 1;
2955 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
2956 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2957 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
2958 if ((bcc_ptr + (2 * length)) -
2959 pByteArea(smb_buffer_response) <=
2960 BCC(smb_buffer_response)) {
2961 if(tcon->nativeFileSystem)
2962 kfree(tcon->nativeFileSystem);
2963 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07002964 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 cifs_strfromUCS_le(tcon->nativeFileSystem,
2966 (wchar_t *) bcc_ptr,
2967 length, nls_codepage);
2968 bcc_ptr += 2 * length;
2969 bcc_ptr[0] = 0; /* null terminate the string */
2970 bcc_ptr[1] = 0;
2971 bcc_ptr += 2;
2972 }
2973 /* else do not bother copying these informational fields */
2974 } else {
2975 length = strnlen(bcc_ptr, 1024);
2976 if ((bcc_ptr + length) -
2977 pByteArea(smb_buffer_response) <=
2978 BCC(smb_buffer_response)) {
2979 if(tcon->nativeFileSystem)
2980 kfree(tcon->nativeFileSystem);
2981 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07002982 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 strncpy(tcon->nativeFileSystem, bcc_ptr,
2984 length);
2985 }
2986 /* else do not bother copying these informational fields */
2987 }
2988 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2989 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2990 } else if ((rc == 0) && tcon == NULL) {
2991 /* all we need to save for IPC$ connection */
2992 ses->ipc_tid = smb_buffer_response->Tid;
2993 }
2994
2995 if (smb_buffer)
2996 cifs_buf_release(smb_buffer);
2997 return rc;
2998}
2999
3000int
3001cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3002{
3003 int rc = 0;
3004 int xid;
3005 struct cifsSesInfo *ses = NULL;
3006 struct task_struct *cifsd_task;
3007
3008 xid = GetXid();
3009
3010 if (cifs_sb->tcon) {
3011 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3012 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3013 if (rc == -EBUSY) {
3014 FreeXid(xid);
3015 return 0;
3016 }
3017 tconInfoFree(cifs_sb->tcon);
3018 if ((ses) && (ses->server)) {
3019 /* save off task so we do not refer to ses later */
3020 cifsd_task = ses->server->tsk;
3021 cFYI(1, ("About to do SMBLogoff "));
3022 rc = CIFSSMBLogoff(xid, ses);
3023 if (rc == -EBUSY) {
3024 FreeXid(xid);
3025 return 0;
3026 } else if (rc == -ESHUTDOWN) {
3027 cFYI(1,("Waking up socket by sending it signal"));
3028 if(cifsd_task)
3029 send_sig(SIGKILL,cifsd_task,1);
3030 rc = 0;
3031 } /* else - we have an smb session
3032 left on this socket do not kill cifsd */
3033 } else
3034 cFYI(1, ("No session or bad tcon"));
3035 }
3036
3037 cifs_sb->tcon = NULL;
3038 if (ses) {
3039 set_current_state(TASK_INTERRUPTIBLE);
3040 schedule_timeout(HZ / 2);
3041 }
3042 if (ses)
3043 sesInfoFree(ses);
3044
3045 FreeXid(xid);
3046 return rc; /* BB check if we should always return zero here */
3047}
3048
3049int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3050 struct nls_table * nls_info)
3051{
3052 int rc = 0;
3053 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3054 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003055 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
3057 /* what if server changes its buffer size after dropping the session? */
3058 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3059 rc = CIFSSMBNegotiate(xid, pSesInfo);
3060 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3061 rc = CIFSSMBNegotiate(xid, pSesInfo);
3062 if(rc == -EAGAIN)
3063 rc = -EHOSTDOWN;
3064 }
3065 if(rc == 0) {
3066 spin_lock(&GlobalMid_Lock);
3067 if(pSesInfo->server->tcpStatus != CifsExiting)
3068 pSesInfo->server->tcpStatus = CifsGood;
3069 else
3070 rc = -EHOSTDOWN;
3071 spin_unlock(&GlobalMid_Lock);
3072
3073 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003074 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 }
3076 if (!rc) {
3077 pSesInfo->capabilities = pSesInfo->server->capabilities;
3078 if(linuxExtEnabled == 0)
3079 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003080 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3082 pSesInfo->server->secMode,
3083 pSesInfo->server->capabilities,
3084 pSesInfo->server->timeZone));
3085 if (extended_security
3086 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3087 && (pSesInfo->server->secType == NTLMSSP)) {
3088 cFYI(1, ("New style sesssetup "));
3089 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3090 NULL /* security blob */,
3091 0 /* blob length */,
3092 nls_info);
3093 } else if (extended_security
3094 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3095 && (pSesInfo->server->secType == RawNTLMSSP)) {
3096 cFYI(1, ("NTLMSSP sesssetup "));
3097 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3098 pSesInfo,
3099 &ntlmv2_flag,
3100 nls_info);
3101 if (!rc) {
3102 if(ntlmv2_flag) {
3103 char * v2_response;
3104 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3105 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3106 nls_info)) {
3107 rc = -ENOMEM;
3108 goto ss_err_exit;
3109 } else
3110 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3111 if(v2_response) {
3112 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003113 /* if(first_time)
3114 cifs_calculate_ntlmv2_mac_key(
3115 pSesInfo->server->mac_signing_key,
3116 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 kfree(v2_response);
3118 /* BB Put dummy sig in SessSetup PDU? */
3119 } else {
3120 rc = -ENOMEM;
3121 goto ss_err_exit;
3122 }
3123
3124 } else {
3125 SMBNTencrypt(pSesInfo->password,
3126 pSesInfo->server->cryptKey,
3127 ntlm_session_key);
3128
Steve Frenchad009ac2005-04-28 22:41:05 -07003129 if(first_time)
3130 cifs_calculate_mac_key(
3131 pSesInfo->server->mac_signing_key,
3132 ntlm_session_key,
3133 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 }
3135 /* for better security the weaker lanman hash not sent
3136 in AuthSessSetup so we no longer calculate it */
3137
3138 rc = CIFSNTLMSSPAuthSessSetup(xid,
3139 pSesInfo,
3140 ntlm_session_key,
3141 ntlmv2_flag,
3142 nls_info);
3143 }
3144 } else { /* old style NTLM 0.12 session setup */
3145 SMBNTencrypt(pSesInfo->password,
3146 pSesInfo->server->cryptKey,
3147 ntlm_session_key);
3148
Steve Frenchad009ac2005-04-28 22:41:05 -07003149 if(first_time)
3150 cifs_calculate_mac_key(
3151 pSesInfo->server->mac_signing_key,
3152 ntlm_session_key, pSesInfo->password);
3153
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 rc = CIFSSessSetup(xid, pSesInfo,
3155 ntlm_session_key, nls_info);
3156 }
3157 if (rc) {
3158 cERROR(1,("Send error in SessSetup = %d",rc));
3159 } else {
3160 cFYI(1,("CIFS Session Established successfully"));
3161 pSesInfo->status = CifsGood;
3162 }
3163 }
3164ss_err_exit:
3165 return rc;
3166}
3167