blob: d5d49b584db48329e89c48c6c542b1d20d897e0e [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;
362 for (total_read = 0;
363 total_read < pdu_length;
364 total_read += length) {
365 length = kernel_recvmsg(csocket, &smb_msg,
366 &iov, 1,
367 pdu_length - total_read, 0);
368 if (length == 0) {
369 cERROR(1,
370 ("Zero length receive when expecting %d ",
371 pdu_length - total_read));
372 cifs_reconnect(server);
373 csocket = server->ssocket;
374 wake_up(&server->response_q);
375 continue;
376 }
377 }
378 length += 4; /* account for rfc1002 hdr */
379 }
380
381 dump_smb(smb_buffer, length);
382 if (checkSMB
383 (smb_buffer, smb_buffer->Mid, total_read+4)) {
384 cERROR(1, ("Bad SMB Received "));
385 continue;
386 }
387
Steve French09d1db52005-04-28 22:41:08 -0700388 /* BB FIXME - add checkTrans2SMBSecondary() */
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 task_to_wake = NULL;
391 spin_lock(&GlobalMid_Lock);
392 list_for_each(tmp, &server->pending_mid_q) {
393 mid_entry = list_entry(tmp, struct
394 mid_q_entry,
395 qhead);
396
Steve French848f3fc2005-04-28 22:41:07 -0700397 if ((mid_entry->mid == smb_buffer->Mid)
398 && (mid_entry->midState ==
399 MID_REQUEST_SUBMITTED)
400 && (mid_entry->command ==
401 smb_buffer->Command)) {
402 cFYI(1,("Found Mid 0x%x wake up"
403 ,mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 task_to_wake = mid_entry->tsk;
405 mid_entry->resp_buf =
406 smb_buffer;
407 mid_entry->midState =
408 MID_RESPONSE_RECEIVED;
Steve French099a58f2005-04-28 22:41:07 -0700409 if(isLargeBuf)
410 mid_entry->largeBuf = 1;
411 else
412 mid_entry->largeBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 }
414 }
415 spin_unlock(&GlobalMid_Lock);
416 if (task_to_wake) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700417 if(isLargeBuf)
418 bigbuf = NULL;
419 else
420 smallbuf = NULL;
Steve French09d1db52005-04-28 22:41:08 -0700421 smb_buffer = NULL; /* will be freed by users thread after he is done */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 wake_up_process(task_to_wake);
423 } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
424 cERROR(1, ("No task to wake, unknown frame rcvd!"));
425 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
426 }
427 }
428 } else {
429 cFYI(1,
430 ("Frame less than four bytes received %d bytes long.",
431 length));
432 cifs_reconnect(server);
433 csocket = server->ssocket;
434 wake_up(&server->response_q);
435 continue;
436 }
437 }
438 spin_lock(&GlobalMid_Lock);
439 server->tcpStatus = CifsExiting;
440 server->tsk = NULL;
441 atomic_set(&server->inFlight, 0);
442 spin_unlock(&GlobalMid_Lock);
443 /* Although there should not be any requests blocked on
444 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700445 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 to the same server - they now will see the session is in exit state
447 and get out of SendReceive. */
448 wake_up_all(&server->request_q);
449 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700450 msleep(125);
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if(server->ssocket) {
453 sock_release(csocket);
454 server->ssocket = NULL;
455 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700456 /* buffer usuallly freed in free_mid - need to free it here on exit */
457 if (bigbuf != NULL)
458 cifs_buf_release(bigbuf);
459 if (smallbuf != NULL)
460 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
462 read_lock(&GlobalSMBSeslock);
463 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700464 /* loop through server session structures attached to this and
465 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 list_for_each(tmp, &GlobalSMBSessionList) {
467 ses =
468 list_entry(tmp, struct cifsSesInfo,
469 cifsSessionList);
470 if (ses->server == server) {
471 ses->status = CifsExiting;
472 ses->server = NULL;
473 }
474 }
475 read_unlock(&GlobalSMBSeslock);
476 } else {
477 spin_lock(&GlobalMid_Lock);
478 list_for_each(tmp, &server->pending_mid_q) {
479 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
480 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
481 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700482 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 task_to_wake = mid_entry->tsk;
484 if(task_to_wake) {
485 wake_up_process(task_to_wake);
486 }
487 }
488 }
489 spin_unlock(&GlobalMid_Lock);
490 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700492 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 }
494
495 if (list_empty(&server->pending_mid_q)) {
496 /* mpx threads have not exited yet give them
497 at least the smb send timeout time for long ops */
498 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700499 msleep(46);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 /* if threads still have not exited they are probably never
501 coming home not much else we can do but free the memory */
502 }
503 kfree(server);
504
505 write_lock(&GlobalSMBSeslock);
506 atomic_dec(&tcpSesAllocCount);
507 length = tcpSesAllocCount.counter;
508 write_unlock(&GlobalSMBSeslock);
509 if(length > 0) {
510 mempool_resize(cifs_req_poolp,
511 length + cifs_min_rcv,
512 GFP_KERNEL);
513 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700514
515 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 return 0;
517}
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519static int
520cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
521{
522 char *value;
523 char *data;
524 unsigned int temp_len, i, j;
525 char separator[2];
526
527 separator[0] = ',';
528 separator[1] = 0;
529
530 memset(vol->source_rfc1001_name,0x20,15);
531 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
532 /* does not have to be a perfect mapping since the field is
533 informational, only used for servers that do not support
534 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700535 vol->source_rfc1001_name[i] =
536 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 }
538 vol->source_rfc1001_name[15] = 0;
539
540 vol->linux_uid = current->uid; /* current->euid instead? */
541 vol->linux_gid = current->gid;
542 vol->dir_mode = S_IRWXUGO;
543 /* 2767 perms indicate mandatory locking support */
544 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
545
546 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
547 vol->rw = TRUE;
548
549 if (!options)
550 return 1;
551
552 if(strncmp(options,"sep=",4) == 0) {
553 if(options[4] != 0) {
554 separator[0] = options[4];
555 options += 5;
556 } else {
557 cFYI(1,("Null separator not allowed"));
558 }
559 }
560
561 while ((data = strsep(&options, separator)) != NULL) {
562 if (!*data)
563 continue;
564 if ((value = strchr(data, '=')) != NULL)
565 *value++ = '\0';
566
567 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
568 vol->no_xattr = 0;
569 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
570 vol->no_xattr = 1;
571 } else if (strnicmp(data, "user", 4) == 0) {
572 if (!value || !*value) {
573 printk(KERN_WARNING
574 "CIFS: invalid or missing username\n");
575 return 1; /* needs_arg; */
576 }
577 if (strnlen(value, 200) < 200) {
578 vol->username = value;
579 } else {
580 printk(KERN_WARNING "CIFS: username too long\n");
581 return 1;
582 }
583 } else if (strnicmp(data, "pass", 4) == 0) {
584 if (!value) {
585 vol->password = NULL;
586 continue;
587 } else if(value[0] == 0) {
588 /* check if string begins with double comma
589 since that would mean the password really
590 does start with a comma, and would not
591 indicate an empty string */
592 if(value[1] != separator[0]) {
593 vol->password = NULL;
594 continue;
595 }
596 }
597 temp_len = strlen(value);
598 /* removed password length check, NTLM passwords
599 can be arbitrarily long */
600
601 /* if comma in password, the string will be
602 prematurely null terminated. Commas in password are
603 specified across the cifs mount interface by a double
604 comma ie ,, and a comma used as in other cases ie ','
605 as a parameter delimiter/separator is single and due
606 to the strsep above is temporarily zeroed. */
607
608 /* NB: password legally can have multiple commas and
609 the only illegal character in a password is null */
610
Steve French09d1db52005-04-28 22:41:08 -0700611 if ((value[temp_len] == 0) &&
612 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 /* reinsert comma */
614 value[temp_len] = separator[0];
615 temp_len+=2; /* move after the second comma */
616 while(value[temp_len] != 0) {
617 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700618 if (value[temp_len+1] ==
619 separator[0]) {
620 /* skip second comma */
621 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 } else {
623 /* single comma indicating start
624 of next parm */
625 break;
626 }
627 }
628 temp_len++;
629 }
630 if(value[temp_len] == 0) {
631 options = NULL;
632 } else {
633 value[temp_len] = 0;
634 /* point option to start of next parm */
635 options = value + temp_len + 1;
636 }
637 /* go from value to value + temp_len condensing
638 double commas to singles. Note that this ends up
639 allocating a few bytes too many, which is ok */
Steve French433dc242005-04-28 22:41:08 -0700640 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
641 if(vol->password == NULL) {
642 printk("CIFS: no memory for pass\n");
643 return 1;
644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 for(i=0,j=0;i<temp_len;i++,j++) {
646 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700647 if(value[i] == separator[0]
648 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 /* skip second comma */
650 i++;
651 }
652 }
653 vol->password[j] = 0;
654 } else {
Steve French09d1db52005-04-28 22:41:08 -0700655 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700656 if(vol->password == NULL) {
657 printk("CIFS: no memory for pass\n");
658 return 1;
659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 strcpy(vol->password, value);
661 }
662 } else if (strnicmp(data, "ip", 2) == 0) {
663 if (!value || !*value) {
664 vol->UNCip = NULL;
665 } else if (strnlen(value, 35) < 35) {
666 vol->UNCip = value;
667 } else {
668 printk(KERN_WARNING "CIFS: ip address too long\n");
669 return 1;
670 }
671 } else if ((strnicmp(data, "unc", 3) == 0)
672 || (strnicmp(data, "target", 6) == 0)
673 || (strnicmp(data, "path", 4) == 0)) {
674 if (!value || !*value) {
675 printk(KERN_WARNING
676 "CIFS: invalid path to network resource\n");
677 return 1; /* needs_arg; */
678 }
679 if ((temp_len = strnlen(value, 300)) < 300) {
680 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
681 if(vol->UNC == NULL)
682 return 1;
683 strcpy(vol->UNC,value);
684 if (strncmp(vol->UNC, "//", 2) == 0) {
685 vol->UNC[0] = '\\';
686 vol->UNC[1] = '\\';
687 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
688 printk(KERN_WARNING
689 "CIFS: UNC Path does not begin with // or \\\\ \n");
690 return 1;
691 }
692 } else {
693 printk(KERN_WARNING "CIFS: UNC name too long\n");
694 return 1;
695 }
696 } else if ((strnicmp(data, "domain", 3) == 0)
697 || (strnicmp(data, "workgroup", 5) == 0)) {
698 if (!value || !*value) {
699 printk(KERN_WARNING "CIFS: invalid domain name\n");
700 return 1; /* needs_arg; */
701 }
702 /* BB are there cases in which a comma can be valid in
703 a domain name and need special handling? */
704 if (strnlen(value, 65) < 65) {
705 vol->domainname = value;
706 cFYI(1, ("Domain name set"));
707 } else {
708 printk(KERN_WARNING "CIFS: domain name too long\n");
709 return 1;
710 }
711 } else if (strnicmp(data, "iocharset", 9) == 0) {
712 if (!value || !*value) {
713 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
714 return 1; /* needs_arg; */
715 }
716 if (strnlen(value, 65) < 65) {
717 if(strnicmp(value,"default",7))
718 vol->iocharset = value;
719 /* if iocharset not set load_nls_default used by caller */
720 cFYI(1, ("iocharset set to %s",value));
721 } else {
722 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
723 return 1;
724 }
725 } else if (strnicmp(data, "uid", 3) == 0) {
726 if (value && *value) {
727 vol->linux_uid =
728 simple_strtoul(value, &value, 0);
729 }
730 } else if (strnicmp(data, "gid", 3) == 0) {
731 if (value && *value) {
732 vol->linux_gid =
733 simple_strtoul(value, &value, 0);
734 }
735 } else if (strnicmp(data, "file_mode", 4) == 0) {
736 if (value && *value) {
737 vol->file_mode =
738 simple_strtoul(value, &value, 0);
739 }
740 } else if (strnicmp(data, "dir_mode", 4) == 0) {
741 if (value && *value) {
742 vol->dir_mode =
743 simple_strtoul(value, &value, 0);
744 }
745 } else if (strnicmp(data, "dirmode", 4) == 0) {
746 if (value && *value) {
747 vol->dir_mode =
748 simple_strtoul(value, &value, 0);
749 }
750 } else if (strnicmp(data, "port", 4) == 0) {
751 if (value && *value) {
752 vol->port =
753 simple_strtoul(value, &value, 0);
754 }
755 } else if (strnicmp(data, "rsize", 5) == 0) {
756 if (value && *value) {
757 vol->rsize =
758 simple_strtoul(value, &value, 0);
759 }
760 } else if (strnicmp(data, "wsize", 5) == 0) {
761 if (value && *value) {
762 vol->wsize =
763 simple_strtoul(value, &value, 0);
764 }
765 } else if (strnicmp(data, "sockopt", 5) == 0) {
766 if (value && *value) {
767 vol->sockopt =
768 simple_strtoul(value, &value, 0);
769 }
770 } else if (strnicmp(data, "netbiosname", 4) == 0) {
771 if (!value || !*value || (*value == ' ')) {
772 cFYI(1,("invalid (empty) netbiosname specified"));
773 } else {
774 memset(vol->source_rfc1001_name,0x20,15);
775 for(i=0;i<15;i++) {
776 /* BB are there cases in which a comma can be
777 valid in this workstation netbios name (and need
778 special handling)? */
779
780 /* We do not uppercase netbiosname for user */
781 if (value[i]==0)
782 break;
783 else
784 vol->source_rfc1001_name[i] = value[i];
785 }
786 /* The string has 16th byte zero still from
787 set at top of the function */
788 if((i==15) && (value[i] != 0))
789 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
790 }
791 } else if (strnicmp(data, "credentials", 4) == 0) {
792 /* ignore */
793 } else if (strnicmp(data, "version", 3) == 0) {
794 /* ignore */
795 } else if (strnicmp(data, "guest",5) == 0) {
796 /* ignore */
797 } else if (strnicmp(data, "rw", 2) == 0) {
798 vol->rw = TRUE;
799 } else if ((strnicmp(data, "suid", 4) == 0) ||
800 (strnicmp(data, "nosuid", 6) == 0) ||
801 (strnicmp(data, "exec", 4) == 0) ||
802 (strnicmp(data, "noexec", 6) == 0) ||
803 (strnicmp(data, "nodev", 5) == 0) ||
804 (strnicmp(data, "noauto", 6) == 0) ||
805 (strnicmp(data, "dev", 3) == 0)) {
806 /* The mount tool or mount.cifs helper (if present)
807 uses these opts to set flags, and the flags are read
808 by the kernel vfs layer before we get here (ie
809 before read super) so there is no point trying to
810 parse these options again and set anything and it
811 is ok to just ignore them */
812 continue;
813 } else if (strnicmp(data, "ro", 2) == 0) {
814 vol->rw = FALSE;
815 } else if (strnicmp(data, "hard", 4) == 0) {
816 vol->retry = 1;
817 } else if (strnicmp(data, "soft", 4) == 0) {
818 vol->retry = 0;
819 } else if (strnicmp(data, "perm", 4) == 0) {
820 vol->noperm = 0;
821 } else if (strnicmp(data, "noperm", 6) == 0) {
822 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -0700823 } else if (strnicmp(data, "mapchars", 8) == 0) {
824 vol->remap = 1;
825 } else if (strnicmp(data, "nomapchars", 10) == 0) {
826 vol->remap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 } else if (strnicmp(data, "setuids", 7) == 0) {
828 vol->setuids = 1;
829 } else if (strnicmp(data, "nosetuids", 9) == 0) {
830 vol->setuids = 0;
831 } else if (strnicmp(data, "nohard", 6) == 0) {
832 vol->retry = 0;
833 } else if (strnicmp(data, "nosoft", 6) == 0) {
834 vol->retry = 1;
835 } else if (strnicmp(data, "nointr", 6) == 0) {
836 vol->intr = 0;
837 } else if (strnicmp(data, "intr", 4) == 0) {
838 vol->intr = 1;
839 } else if (strnicmp(data, "serverino",7) == 0) {
840 vol->server_ino = 1;
841 } else if (strnicmp(data, "noserverino",9) == 0) {
842 vol->server_ino = 0;
843 } else if (strnicmp(data, "acl",3) == 0) {
844 vol->no_psx_acl = 0;
845 } else if (strnicmp(data, "noacl",5) == 0) {
846 vol->no_psx_acl = 1;
847 } else if (strnicmp(data, "direct",6) == 0) {
848 vol->direct_io = 1;
849 } else if (strnicmp(data, "forcedirectio",13) == 0) {
850 vol->direct_io = 1;
851 } else if (strnicmp(data, "in6_addr",8) == 0) {
852 if (!value || !*value) {
853 vol->in6_addr = NULL;
854 } else if (strnlen(value, 49) == 48) {
855 vol->in6_addr = value;
856 } else {
857 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
858 return 1;
859 }
860 } else if (strnicmp(data, "noac", 4) == 0) {
861 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
862 } else
863 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
864 }
865 if (vol->UNC == NULL) {
866 if(devname == NULL) {
867 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
868 return 1;
869 }
870 if ((temp_len = strnlen(devname, 300)) < 300) {
871 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
872 if(vol->UNC == NULL)
873 return 1;
874 strcpy(vol->UNC,devname);
875 if (strncmp(vol->UNC, "//", 2) == 0) {
876 vol->UNC[0] = '\\';
877 vol->UNC[1] = '\\';
878 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
879 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
880 return 1;
881 }
882 } else {
883 printk(KERN_WARNING "CIFS: UNC name too long\n");
884 return 1;
885 }
886 }
887 if(vol->UNCip == NULL)
888 vol->UNCip = &vol->UNC[2];
889
890 return 0;
891}
892
893static struct cifsSesInfo *
894cifs_find_tcp_session(struct in_addr * target_ip_addr,
895 struct in6_addr *target_ip6_addr,
896 char *userName, struct TCP_Server_Info **psrvTcp)
897{
898 struct list_head *tmp;
899 struct cifsSesInfo *ses;
900 *psrvTcp = NULL;
901 read_lock(&GlobalSMBSeslock);
902
903 list_for_each(tmp, &GlobalSMBSessionList) {
904 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
905 if (ses->server) {
906 if((target_ip_addr &&
907 (ses->server->addr.sockAddr.sin_addr.s_addr
908 == target_ip_addr->s_addr)) || (target_ip6_addr
909 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
910 target_ip6_addr,sizeof(*target_ip6_addr)))){
911 /* BB lock server and tcp session and increment use count here?? */
912 *psrvTcp = ses->server; /* found a match on the TCP session */
913 /* BB check if reconnection needed */
914 if (strncmp
915 (ses->userName, userName,
916 MAX_USERNAME_SIZE) == 0){
917 read_unlock(&GlobalSMBSeslock);
918 return ses; /* found exact match on both tcp and SMB sessions */
919 }
920 }
921 }
922 /* else tcp and smb sessions need reconnection */
923 }
924 read_unlock(&GlobalSMBSeslock);
925 return NULL;
926}
927
928static struct cifsTconInfo *
929find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
930{
931 struct list_head *tmp;
932 struct cifsTconInfo *tcon;
933
934 read_lock(&GlobalSMBSeslock);
935 list_for_each(tmp, &GlobalTreeConnectionList) {
936 cFYI(1, ("Next tcon - "));
937 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
938 if (tcon->ses) {
939 if (tcon->ses->server) {
940 cFYI(1,
941 (" old ip addr: %x == new ip %x ?",
942 tcon->ses->server->addr.sockAddr.sin_addr.
943 s_addr, new_target_ip_addr));
944 if (tcon->ses->server->addr.sockAddr.sin_addr.
945 s_addr == new_target_ip_addr) {
946 /* BB lock tcon and server and tcp session and increment use count here? */
947 /* found a match on the TCP session */
948 /* BB check if reconnection needed */
949 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
950 tcon->treeName, uncName));
951 if (strncmp
952 (tcon->treeName, uncName,
953 MAX_TREE_SIZE) == 0) {
954 cFYI(1,
955 ("Matched UNC, old user: %s == new: %s ?",
956 tcon->treeName, uncName));
957 if (strncmp
958 (tcon->ses->userName,
959 userName,
960 MAX_USERNAME_SIZE) == 0) {
961 read_unlock(&GlobalSMBSeslock);
962 return tcon;/* also matched user (smb session)*/
963 }
964 }
965 }
966 }
967 }
968 }
969 read_unlock(&GlobalSMBSeslock);
970 return NULL;
971}
972
973int
974connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -0700975 const char *old_path, const struct nls_table *nls_codepage,
976 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 unsigned char *referrals = NULL;
979 unsigned int num_referrals;
980 int rc = 0;
981
982 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -0700983 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 /* BB Add in code to: if valid refrl, if not ip address contact
986 the helper that resolves tcp names, mount to it, try to
987 tcon to it unmount it if fail */
988
989 if(referrals)
990 kfree(referrals);
991
992 return rc;
993}
994
995int
996get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
997 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -0700998 unsigned int *pnum_referrals,
999 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
1001 char *temp_unc;
1002 int rc = 0;
1003
1004 *pnum_referrals = 0;
1005
1006 if (pSesInfo->ipc_tid == 0) {
1007 temp_unc = kmalloc(2 /* for slashes */ +
1008 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1009 + 1 + 4 /* slash IPC$ */ + 2,
1010 GFP_KERNEL);
1011 if (temp_unc == NULL)
1012 return -ENOMEM;
1013 temp_unc[0] = '\\';
1014 temp_unc[1] = '\\';
1015 strcpy(temp_unc + 2, pSesInfo->serverName);
1016 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1017 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1018 cFYI(1,
1019 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1020 kfree(temp_unc);
1021 }
1022 if (rc == 0)
1023 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001024 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 return rc;
1027}
1028
1029/* See RFC1001 section 14 on representation of Netbios names */
1030static void rfc1002mangle(char * target,char * source, unsigned int length)
1031{
1032 unsigned int i,j;
1033
1034 for(i=0,j=0;i<(length);i++) {
1035 /* mask a nibble at a time and encode */
1036 target[j] = 'A' + (0x0F & (source[i] >> 4));
1037 target[j+1] = 'A' + (0x0F & source[i]);
1038 j+=2;
1039 }
1040
1041}
1042
1043
1044static int
1045ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1046 char * netbios_name)
1047{
1048 int rc = 0;
1049 int connected = 0;
1050 __be16 orig_port = 0;
1051
1052 if(*csocket == NULL) {
1053 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1054 if (rc < 0) {
1055 cERROR(1, ("Error %d creating socket",rc));
1056 *csocket = NULL;
1057 return rc;
1058 } else {
1059 /* BB other socket options to set KEEPALIVE, NODELAY? */
1060 cFYI(1,("Socket created"));
1061 (*csocket)->sk->sk_allocation = GFP_NOFS;
1062 }
1063 }
1064
1065 psin_server->sin_family = AF_INET;
1066 if(psin_server->sin_port) { /* user overrode default port */
1067 rc = (*csocket)->ops->connect(*csocket,
1068 (struct sockaddr *) psin_server,
1069 sizeof (struct sockaddr_in),0);
1070 if (rc >= 0)
1071 connected = 1;
1072 }
1073
1074 if(!connected) {
1075 /* save original port so we can retry user specified port
1076 later if fall back ports fail this time */
1077 orig_port = psin_server->sin_port;
1078
1079 /* do not retry on the same port we just failed on */
1080 if(psin_server->sin_port != htons(CIFS_PORT)) {
1081 psin_server->sin_port = htons(CIFS_PORT);
1082
1083 rc = (*csocket)->ops->connect(*csocket,
1084 (struct sockaddr *) psin_server,
1085 sizeof (struct sockaddr_in),0);
1086 if (rc >= 0)
1087 connected = 1;
1088 }
1089 }
1090 if (!connected) {
1091 psin_server->sin_port = htons(RFC1001_PORT);
1092 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1093 psin_server, sizeof (struct sockaddr_in),0);
1094 if (rc >= 0)
1095 connected = 1;
1096 }
1097
1098 /* give up here - unless we want to retry on different
1099 protocol families some day */
1100 if (!connected) {
1101 if(orig_port)
1102 psin_server->sin_port = orig_port;
1103 cFYI(1,("Error %d connecting to server via ipv4",rc));
1104 sock_release(*csocket);
1105 *csocket = NULL;
1106 return rc;
1107 }
1108 /* Eventually check for other socket options to change from
1109 the default. sock_setsockopt not used because it expects
1110 user space buffer */
1111 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1112
1113 /* send RFC1001 sessinit */
1114
1115 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1116 /* some servers require RFC1001 sessinit before sending
1117 negprot - BB check reconnection in case where second
1118 sessinit is sent but no second negprot */
1119 struct rfc1002_session_packet * ses_init_buf;
1120 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001121 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 if(ses_init_buf) {
1123 ses_init_buf->trailer.session_req.called_len = 32;
1124 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1125 DEFAULT_CIFS_CALLED_NAME,16);
1126 ses_init_buf->trailer.session_req.calling_len = 32;
1127 /* calling name ends in null (byte 16) from old smb
1128 convention. */
1129 if(netbios_name && (netbios_name[0] !=0)) {
1130 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1131 netbios_name,16);
1132 } else {
1133 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1134 "LINUX_CIFS_CLNT",16);
1135 }
1136 ses_init_buf->trailer.session_req.scope1 = 0;
1137 ses_init_buf->trailer.session_req.scope2 = 0;
1138 smb_buf = (struct smb_hdr *)ses_init_buf;
1139 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1140 smb_buf->smb_buf_length = 0x81000044;
1141 rc = smb_send(*csocket, smb_buf, 0x44,
1142 (struct sockaddr *)psin_server);
1143 kfree(ses_init_buf);
1144 }
1145 /* else the negprot may still work without this
1146 even though malloc failed */
1147
1148 }
1149
1150 return rc;
1151}
1152
1153static int
1154ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1155{
1156 int rc = 0;
1157 int connected = 0;
1158 __be16 orig_port = 0;
1159
1160 if(*csocket == NULL) {
1161 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1162 if (rc < 0) {
1163 cERROR(1, ("Error %d creating ipv6 socket",rc));
1164 *csocket = NULL;
1165 return rc;
1166 } else {
1167 /* BB other socket options to set KEEPALIVE, NODELAY? */
1168 cFYI(1,("ipv6 Socket created"));
1169 (*csocket)->sk->sk_allocation = GFP_NOFS;
1170 }
1171 }
1172
1173 psin_server->sin6_family = AF_INET6;
1174
1175 if(psin_server->sin6_port) { /* user overrode default port */
1176 rc = (*csocket)->ops->connect(*csocket,
1177 (struct sockaddr *) psin_server,
1178 sizeof (struct sockaddr_in6),0);
1179 if (rc >= 0)
1180 connected = 1;
1181 }
1182
1183 if(!connected) {
1184 /* save original port so we can retry user specified port
1185 later if fall back ports fail this time */
1186
1187 orig_port = psin_server->sin6_port;
1188 /* do not retry on the same port we just failed on */
1189 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1190 psin_server->sin6_port = htons(CIFS_PORT);
1191
1192 rc = (*csocket)->ops->connect(*csocket,
1193 (struct sockaddr *) psin_server,
1194 sizeof (struct sockaddr_in6),0);
1195 if (rc >= 0)
1196 connected = 1;
1197 }
1198 }
1199 if (!connected) {
1200 psin_server->sin6_port = htons(RFC1001_PORT);
1201 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1202 psin_server, sizeof (struct sockaddr_in6),0);
1203 if (rc >= 0)
1204 connected = 1;
1205 }
1206
1207 /* give up here - unless we want to retry on different
1208 protocol families some day */
1209 if (!connected) {
1210 if(orig_port)
1211 psin_server->sin6_port = orig_port;
1212 cFYI(1,("Error %d connecting to server via ipv6",rc));
1213 sock_release(*csocket);
1214 *csocket = NULL;
1215 return rc;
1216 }
1217 /* Eventually check for other socket options to change from
1218 the default. sock_setsockopt not used because it expects
1219 user space buffer */
1220 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1221
1222 return rc;
1223}
1224
1225int
1226cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1227 char *mount_data, const char *devname)
1228{
1229 int rc = 0;
1230 int xid;
1231 int address_type = AF_INET;
1232 struct socket *csocket = NULL;
1233 struct sockaddr_in sin_server;
1234 struct sockaddr_in6 sin_server6;
1235 struct smb_vol volume_info;
1236 struct cifsSesInfo *pSesInfo = NULL;
1237 struct cifsSesInfo *existingCifsSes = NULL;
1238 struct cifsTconInfo *tcon = NULL;
1239 struct TCP_Server_Info *srvTcp = NULL;
1240
1241 xid = GetXid();
1242
1243/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1244
1245 memset(&volume_info,0,sizeof(struct smb_vol));
1246 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1247 if(volume_info.UNC)
1248 kfree(volume_info.UNC);
1249 if(volume_info.password)
1250 kfree(volume_info.password);
1251 FreeXid(xid);
1252 return -EINVAL;
1253 }
1254
1255 if (volume_info.username) {
1256 /* BB fixme parse for domain name here */
1257 cFYI(1, ("Username: %s ", volume_info.username));
1258
1259 } else {
1260 cifserror("No username specified ");
1261 /* In userspace mount helper we can get user name from alternate
1262 locations such as env variables and files on disk */
1263 if(volume_info.UNC)
1264 kfree(volume_info.UNC);
1265 if(volume_info.password)
1266 kfree(volume_info.password);
1267 FreeXid(xid);
1268 return -EINVAL;
1269 }
1270
1271 if (volume_info.UNCip && volume_info.UNC) {
1272 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1273
1274 if(rc <= 0) {
1275 /* not ipv4 address, try ipv6 */
1276 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1277 if(rc > 0)
1278 address_type = AF_INET6;
1279 } else {
1280 address_type = AF_INET;
1281 }
1282
1283 if(rc <= 0) {
1284 /* we failed translating address */
1285 if(volume_info.UNC)
1286 kfree(volume_info.UNC);
1287 if(volume_info.password)
1288 kfree(volume_info.password);
1289 FreeXid(xid);
1290 return -EINVAL;
1291 }
1292
1293 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1294 /* success */
1295 rc = 0;
1296 } else if (volume_info.UNCip){
1297 /* BB using ip addr as server name connect to the DFS root below */
1298 cERROR(1,("Connecting to DFS root not implemented yet"));
1299 if(volume_info.UNC)
1300 kfree(volume_info.UNC);
1301 if(volume_info.password)
1302 kfree(volume_info.password);
1303 FreeXid(xid);
1304 return -EINVAL;
1305 } else /* which servers DFS root would we conect to */ {
1306 cERROR(1,
1307 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1308 if(volume_info.UNC)
1309 kfree(volume_info.UNC);
1310 if(volume_info.password)
1311 kfree(volume_info.password);
1312 FreeXid(xid);
1313 return -EINVAL;
1314 }
1315
1316 /* this is needed for ASCII cp to Unicode converts */
1317 if(volume_info.iocharset == NULL) {
1318 cifs_sb->local_nls = load_nls_default();
1319 /* load_nls_default can not return null */
1320 } else {
1321 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1322 if(cifs_sb->local_nls == NULL) {
1323 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1324 if(volume_info.UNC)
1325 kfree(volume_info.UNC);
1326 if(volume_info.password)
1327 kfree(volume_info.password);
1328 FreeXid(xid);
1329 return -ELIBACC;
1330 }
1331 }
1332
1333 if(address_type == AF_INET)
1334 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1335 NULL /* no ipv6 addr */,
1336 volume_info.username, &srvTcp);
1337 else if(address_type == AF_INET6)
1338 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1339 &sin_server6.sin6_addr,
1340 volume_info.username, &srvTcp);
1341 else {
1342 if(volume_info.UNC)
1343 kfree(volume_info.UNC);
1344 if(volume_info.password)
1345 kfree(volume_info.password);
1346 FreeXid(xid);
1347 return -EINVAL;
1348 }
1349
1350
1351 if (srvTcp) {
1352 cFYI(1, ("Existing tcp session with server found "));
1353 } else { /* create socket */
1354 if(volume_info.port)
1355 sin_server.sin_port = htons(volume_info.port);
1356 else
1357 sin_server.sin_port = 0;
1358 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1359 if (rc < 0) {
1360 cERROR(1,
1361 ("Error connecting to IPv4 socket. Aborting operation"));
1362 if(csocket != NULL)
1363 sock_release(csocket);
1364 if(volume_info.UNC)
1365 kfree(volume_info.UNC);
1366 if(volume_info.password)
1367 kfree(volume_info.password);
1368 FreeXid(xid);
1369 return rc;
1370 }
1371
1372 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1373 if (srvTcp == NULL) {
1374 rc = -ENOMEM;
1375 sock_release(csocket);
1376 if(volume_info.UNC)
1377 kfree(volume_info.UNC);
1378 if(volume_info.password)
1379 kfree(volume_info.password);
1380 FreeXid(xid);
1381 return rc;
1382 } else {
1383 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1384 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1385 atomic_set(&srvTcp->inFlight,0);
1386 /* BB Add code for ipv6 case too */
1387 srvTcp->ssocket = csocket;
1388 srvTcp->protocolType = IPV4;
1389 init_waitqueue_head(&srvTcp->response_q);
1390 init_waitqueue_head(&srvTcp->request_q);
1391 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1392 /* at this point we are the only ones with the pointer
1393 to the struct since the kernel thread not created yet
1394 so no need to spinlock this init of tcpStatus */
1395 srvTcp->tcpStatus = CifsNew;
1396 init_MUTEX(&srvTcp->tcpSem);
1397 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1398 CLONE_FS | CLONE_FILES | CLONE_VM);
1399 if(rc < 0) {
1400 rc = -ENOMEM;
1401 sock_release(csocket);
1402 if(volume_info.UNC)
1403 kfree(volume_info.UNC);
1404 if(volume_info.password)
1405 kfree(volume_info.password);
1406 FreeXid(xid);
1407 return rc;
1408 } else
1409 rc = 0;
1410 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001411 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413 }
1414
1415 if (existingCifsSes) {
1416 pSesInfo = existingCifsSes;
1417 cFYI(1, ("Existing smb sess found "));
1418 if(volume_info.password)
1419 kfree(volume_info.password);
1420 /* volume_info.UNC freed at end of function */
1421 } else if (!rc) {
1422 cFYI(1, ("Existing smb sess not found "));
1423 pSesInfo = sesInfoAlloc();
1424 if (pSesInfo == NULL)
1425 rc = -ENOMEM;
1426 else {
1427 pSesInfo->server = srvTcp;
1428 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1429 NIPQUAD(sin_server.sin_addr.s_addr));
1430 }
1431
1432 if (!rc){
1433 /* volume_info.password freed at unmount */
1434 if (volume_info.password)
1435 pSesInfo->password = volume_info.password;
1436 if (volume_info.username)
1437 strncpy(pSesInfo->userName,
1438 volume_info.username,MAX_USERNAME_SIZE);
1439 if (volume_info.domainname)
1440 strncpy(pSesInfo->domainName,
1441 volume_info.domainname,MAX_USERNAME_SIZE);
1442 pSesInfo->linux_uid = volume_info.linux_uid;
1443 down(&pSesInfo->sesSem);
1444 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1445 up(&pSesInfo->sesSem);
1446 if(!rc)
1447 atomic_inc(&srvTcp->socketUseCount);
1448 } else
1449 if(volume_info.password)
1450 kfree(volume_info.password);
1451 }
1452
1453 /* search for existing tcon to this server share */
1454 if (!rc) {
1455 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1456 cifs_sb->rsize = volume_info.rsize;
1457 else
1458 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1459 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1460 cifs_sb->wsize = volume_info.wsize;
1461 else
1462 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1463 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1464 cifs_sb->rsize = PAGE_CACHE_SIZE;
1465 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1466 }
1467 cifs_sb->mnt_uid = volume_info.linux_uid;
1468 cifs_sb->mnt_gid = volume_info.linux_gid;
1469 cifs_sb->mnt_file_mode = volume_info.file_mode;
1470 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1471 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1472
1473 if(volume_info.noperm)
1474 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1475 if(volume_info.setuids)
1476 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1477 if(volume_info.server_ino)
1478 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001479 if(volume_info.remap)
1480 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 if(volume_info.no_xattr)
1482 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1483 if(volume_info.direct_io) {
1484 cERROR(1,("mounting share using direct i/o"));
1485 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1486 }
1487
1488 tcon =
1489 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1490 volume_info.username);
1491 if (tcon) {
1492 cFYI(1, ("Found match on UNC path "));
1493 /* we can have only one retry value for a connection
1494 to a share so for resources mounted more than once
1495 to the same server share the last value passed in
1496 for the retry flag is used */
1497 tcon->retry = volume_info.retry;
1498 } else {
1499 tcon = tconInfoAlloc();
1500 if (tcon == NULL)
1501 rc = -ENOMEM;
1502 else {
1503 /* check for null share name ie connect to dfs root */
1504
1505 /* BB check if this works for exactly length three strings */
1506 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1507 && (strchr(volume_info.UNC + 3, '/') ==
1508 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001509 rc = connect_to_dfs_path(xid, pSesInfo,
1510 "", cifs_sb->local_nls,
1511 cifs_sb->mnt_cifs_flags &
1512 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 if(volume_info.UNC)
1514 kfree(volume_info.UNC);
1515 FreeXid(xid);
1516 return -ENODEV;
1517 } else {
1518 rc = CIFSTCon(xid, pSesInfo,
1519 volume_info.UNC,
1520 tcon, cifs_sb->local_nls);
1521 cFYI(1, ("CIFS Tcon rc = %d", rc));
1522 }
1523 if (!rc) {
1524 atomic_inc(&pSesInfo->inUse);
1525 tcon->retry = volume_info.retry;
1526 }
1527 }
1528 }
1529 }
1530 if(pSesInfo) {
1531 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1532 sb->s_maxbytes = (u64) 1 << 63;
1533 } else
1534 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1535 }
1536
1537 sb->s_time_gran = 100;
1538
1539/* on error free sesinfo and tcon struct if needed */
1540 if (rc) {
1541 /* if session setup failed, use count is zero but
1542 we still need to free cifsd thread */
1543 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1544 spin_lock(&GlobalMid_Lock);
1545 srvTcp->tcpStatus = CifsExiting;
1546 spin_unlock(&GlobalMid_Lock);
1547 if(srvTcp->tsk)
1548 send_sig(SIGKILL,srvTcp->tsk,1);
1549 }
1550 /* If find_unc succeeded then rc == 0 so we can not end */
1551 if (tcon) /* up accidently freeing someone elses tcon struct */
1552 tconInfoFree(tcon);
1553 if (existingCifsSes == NULL) {
1554 if (pSesInfo) {
1555 if ((pSesInfo->server) &&
1556 (pSesInfo->status == CifsGood)) {
1557 int temp_rc;
1558 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1559 /* if the socketUseCount is now zero */
1560 if((temp_rc == -ESHUTDOWN) &&
1561 (pSesInfo->server->tsk))
1562 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1563 } else
1564 cFYI(1, ("No session or bad tcon"));
1565 sesInfoFree(pSesInfo);
1566 /* pSesInfo = NULL; */
1567 }
1568 }
1569 } else {
1570 atomic_inc(&tcon->useCount);
1571 cifs_sb->tcon = tcon;
1572 tcon->ses = pSesInfo;
1573
1574 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001575 CIFSSMBQFSDeviceInfo(xid, tcon);
1576 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001578 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 if(!volume_info.no_psx_acl) {
1580 if(CIFS_UNIX_POSIX_ACL_CAP &
1581 le64_to_cpu(tcon->fsUnixInfo.Capability))
1582 cFYI(1,("server negotiated posix acl support"));
1583 sb->s_flags |= MS_POSIXACL;
1584 }
1585 }
1586 }
1587 }
1588
1589 /* volume_info.password is freed above when existing session found
1590 (in which case it is not needed anymore) but when new sesion is created
1591 the password ptr is put in the new session structure (in which case the
1592 password will be freed at unmount time) */
1593 if(volume_info.UNC)
1594 kfree(volume_info.UNC);
1595 FreeXid(xid);
1596 return rc;
1597}
1598
1599static int
1600CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1601 char session_key[CIFS_SESSION_KEY_SIZE],
1602 const struct nls_table *nls_codepage)
1603{
1604 struct smb_hdr *smb_buffer;
1605 struct smb_hdr *smb_buffer_response;
1606 SESSION_SETUP_ANDX *pSMB;
1607 SESSION_SETUP_ANDX *pSMBr;
1608 char *bcc_ptr;
1609 char *user;
1610 char *domain;
1611 int rc = 0;
1612 int remaining_words = 0;
1613 int bytes_returned = 0;
1614 int len;
1615 __u32 capabilities;
1616 __u16 count;
1617
1618 cFYI(1, ("In sesssetup "));
1619 if(ses == NULL)
1620 return -EINVAL;
1621 user = ses->userName;
1622 domain = ses->domainName;
1623 smb_buffer = cifs_buf_get();
1624 if (smb_buffer == NULL) {
1625 return -ENOMEM;
1626 }
1627 smb_buffer_response = smb_buffer;
1628 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1629
1630 /* send SMBsessionSetup here */
1631 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1632 NULL /* no tCon exists yet */ , 13 /* wct */ );
1633
1634 pSMB->req_no_secext.AndXCommand = 0xFF;
1635 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1636 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1637
1638 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1639 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1640
1641 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1642 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1643 if (ses->capabilities & CAP_UNICODE) {
1644 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1645 capabilities |= CAP_UNICODE;
1646 }
1647 if (ses->capabilities & CAP_STATUS32) {
1648 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1649 capabilities |= CAP_STATUS32;
1650 }
1651 if (ses->capabilities & CAP_DFS) {
1652 smb_buffer->Flags2 |= SMBFLG2_DFS;
1653 capabilities |= CAP_DFS;
1654 }
1655 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1656
1657 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1658 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1659
1660 pSMB->req_no_secext.CaseSensitivePasswordLength =
1661 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1662 bcc_ptr = pByteArea(smb_buffer);
1663 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1664 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1665 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1666 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1667
1668 if (ses->capabilities & CAP_UNICODE) {
1669 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1670 *bcc_ptr = 0;
1671 bcc_ptr++;
1672 }
1673 if(user == NULL)
1674 bytes_returned = 0; /* skill null user */
1675 else
1676 bytes_returned =
1677 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1678 nls_codepage);
1679 /* convert number of 16 bit words to bytes */
1680 bcc_ptr += 2 * bytes_returned;
1681 bcc_ptr += 2; /* trailing null */
1682 if (domain == NULL)
1683 bytes_returned =
1684 cifs_strtoUCS((wchar_t *) bcc_ptr,
1685 "CIFS_LINUX_DOM", 32, nls_codepage);
1686 else
1687 bytes_returned =
1688 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1689 nls_codepage);
1690 bcc_ptr += 2 * bytes_returned;
1691 bcc_ptr += 2;
1692 bytes_returned =
1693 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1694 32, nls_codepage);
1695 bcc_ptr += 2 * bytes_returned;
1696 bytes_returned =
1697 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1698 32, nls_codepage);
1699 bcc_ptr += 2 * bytes_returned;
1700 bcc_ptr += 2;
1701 bytes_returned =
1702 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1703 64, nls_codepage);
1704 bcc_ptr += 2 * bytes_returned;
1705 bcc_ptr += 2;
1706 } else {
1707 if(user != NULL) {
1708 strncpy(bcc_ptr, user, 200);
1709 bcc_ptr += strnlen(user, 200);
1710 }
1711 *bcc_ptr = 0;
1712 bcc_ptr++;
1713 if (domain == NULL) {
1714 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1715 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1716 } else {
1717 strncpy(bcc_ptr, domain, 64);
1718 bcc_ptr += strnlen(domain, 64);
1719 *bcc_ptr = 0;
1720 bcc_ptr++;
1721 }
1722 strcpy(bcc_ptr, "Linux version ");
1723 bcc_ptr += strlen("Linux version ");
1724 strcpy(bcc_ptr, system_utsname.release);
1725 bcc_ptr += strlen(system_utsname.release) + 1;
1726 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1727 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1728 }
1729 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1730 smb_buffer->smb_buf_length += count;
1731 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1732
1733 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1734 &bytes_returned, 1);
1735 if (rc) {
1736/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1737 } else if ((smb_buffer_response->WordCount == 3)
1738 || (smb_buffer_response->WordCount == 4)) {
1739 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1740 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1741 if (action & GUEST_LOGIN)
1742 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1743 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1744 cFYI(1, ("UID = %d ", ses->Suid));
1745 /* response can have either 3 or 4 word count - Samba sends 3 */
1746 bcc_ptr = pByteArea(smb_buffer_response);
1747 if ((pSMBr->resp.hdr.WordCount == 3)
1748 || ((pSMBr->resp.hdr.WordCount == 4)
1749 && (blob_len < pSMBr->resp.ByteCount))) {
1750 if (pSMBr->resp.hdr.WordCount == 4)
1751 bcc_ptr += blob_len;
1752
1753 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1754 if ((long) (bcc_ptr) % 2) {
1755 remaining_words =
1756 (BCC(smb_buffer_response) - 1) /2;
1757 bcc_ptr++; /* Unicode strings must be word aligned */
1758 } else {
1759 remaining_words =
1760 BCC(smb_buffer_response) / 2;
1761 }
1762 len =
1763 UniStrnlen((wchar_t *) bcc_ptr,
1764 remaining_words - 1);
1765/* We look for obvious messed up bcc or strings in response so we do not go off
1766 the end since (at least) WIN2K and Windows XP have a major bug in not null
1767 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07001768 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
1769 if(ses->serverOS == NULL)
1770 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 cifs_strfromUCS_le(ses->serverOS,
1772 (wchar_t *)bcc_ptr, len,nls_codepage);
1773 bcc_ptr += 2 * (len + 1);
1774 remaining_words -= len + 1;
1775 ses->serverOS[2 * len] = 0;
1776 ses->serverOS[1 + (2 * len)] = 0;
1777 if (remaining_words > 0) {
1778 len = UniStrnlen((wchar_t *)bcc_ptr,
1779 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07001780 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
1781 if(ses->serverNOS == NULL)
1782 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 cifs_strfromUCS_le(ses->serverNOS,
1784 (wchar_t *)bcc_ptr,len,nls_codepage);
1785 bcc_ptr += 2 * (len + 1);
1786 ses->serverNOS[2 * len] = 0;
1787 ses->serverNOS[1 + (2 * len)] = 0;
1788 if(strncmp(ses->serverNOS,
1789 "NT LAN Manager 4",16) == 0) {
1790 cFYI(1,("NT4 server"));
1791 ses->flags |= CIFS_SES_NT4;
1792 }
1793 remaining_words -= len + 1;
1794 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07001795 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1797 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07001798 kcalloc(1, 2*(len+1),GFP_KERNEL);
1799 if(ses->serverDomain == NULL)
1800 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 cifs_strfromUCS_le(ses->serverDomain,
1802 (wchar_t *)bcc_ptr,len,nls_codepage);
1803 bcc_ptr += 2 * (len + 1);
1804 ses->serverDomain[2*len] = 0;
1805 ses->serverDomain[1+(2*len)] = 0;
1806 } /* else no more room so create dummy domain string */
1807 else
Steve French433dc242005-04-28 22:41:08 -07001808 ses->serverDomain =
1809 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07001811 /* if these kcallocs fail not much we
1812 can do, but better to not fail the
1813 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07001815 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07001817 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 }
1819 } else { /* ASCII */
1820 len = strnlen(bcc_ptr, 1024);
1821 if (((long) bcc_ptr + len) - (long)
1822 pByteArea(smb_buffer_response)
1823 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07001824 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
1825 if(ses->serverOS == NULL)
1826 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 strncpy(ses->serverOS,bcc_ptr, len);
1828
1829 bcc_ptr += len;
1830 bcc_ptr[0] = 0; /* null terminate the string */
1831 bcc_ptr++;
1832
1833 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07001834 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
1835 if(ses->serverNOS == NULL)
1836 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 strncpy(ses->serverNOS, bcc_ptr, len);
1838 bcc_ptr += len;
1839 bcc_ptr[0] = 0;
1840 bcc_ptr++;
1841
1842 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07001843 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
1844 if(ses->serverDomain == NULL)
1845 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 strncpy(ses->serverDomain, bcc_ptr, len);
1847 bcc_ptr += len;
1848 bcc_ptr[0] = 0;
1849 bcc_ptr++;
1850 } else
1851 cFYI(1,
1852 ("Variable field of length %d extends beyond end of smb ",
1853 len));
1854 }
1855 } else {
1856 cERROR(1,
1857 (" Security Blob Length extends beyond end of SMB"));
1858 }
1859 } else {
1860 cERROR(1,
1861 (" Invalid Word count %d: ",
1862 smb_buffer_response->WordCount));
1863 rc = -EIO;
1864 }
Steve French433dc242005-04-28 22:41:08 -07001865sesssetup_nomem: /* do not return an error on nomem for the info strings,
1866 since that could make reconnection harder, and
1867 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (smb_buffer)
1869 cifs_buf_release(smb_buffer);
1870
1871 return rc;
1872}
1873
1874static int
1875CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1876 char *SecurityBlob,int SecurityBlobLength,
1877 const struct nls_table *nls_codepage)
1878{
1879 struct smb_hdr *smb_buffer;
1880 struct smb_hdr *smb_buffer_response;
1881 SESSION_SETUP_ANDX *pSMB;
1882 SESSION_SETUP_ANDX *pSMBr;
1883 char *bcc_ptr;
1884 char *user;
1885 char *domain;
1886 int rc = 0;
1887 int remaining_words = 0;
1888 int bytes_returned = 0;
1889 int len;
1890 __u32 capabilities;
1891 __u16 count;
1892
1893 cFYI(1, ("In spnego sesssetup "));
1894 if(ses == NULL)
1895 return -EINVAL;
1896 user = ses->userName;
1897 domain = ses->domainName;
1898
1899 smb_buffer = cifs_buf_get();
1900 if (smb_buffer == NULL) {
1901 return -ENOMEM;
1902 }
1903 smb_buffer_response = smb_buffer;
1904 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1905
1906 /* send SMBsessionSetup here */
1907 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1908 NULL /* no tCon exists yet */ , 12 /* wct */ );
1909 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1910 pSMB->req.AndXCommand = 0xFF;
1911 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1912 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1913
1914 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1915 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1916
1917 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1918 CAP_EXTENDED_SECURITY;
1919 if (ses->capabilities & CAP_UNICODE) {
1920 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1921 capabilities |= CAP_UNICODE;
1922 }
1923 if (ses->capabilities & CAP_STATUS32) {
1924 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1925 capabilities |= CAP_STATUS32;
1926 }
1927 if (ses->capabilities & CAP_DFS) {
1928 smb_buffer->Flags2 |= SMBFLG2_DFS;
1929 capabilities |= CAP_DFS;
1930 }
1931 pSMB->req.Capabilities = cpu_to_le32(capabilities);
1932
1933 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
1934 bcc_ptr = pByteArea(smb_buffer);
1935 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
1936 bcc_ptr += SecurityBlobLength;
1937
1938 if (ses->capabilities & CAP_UNICODE) {
1939 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
1940 *bcc_ptr = 0;
1941 bcc_ptr++;
1942 }
1943 bytes_returned =
1944 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
1945 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
1946 bcc_ptr += 2; /* trailing null */
1947 if (domain == NULL)
1948 bytes_returned =
1949 cifs_strtoUCS((wchar_t *) bcc_ptr,
1950 "CIFS_LINUX_DOM", 32, nls_codepage);
1951 else
1952 bytes_returned =
1953 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1954 nls_codepage);
1955 bcc_ptr += 2 * bytes_returned;
1956 bcc_ptr += 2;
1957 bytes_returned =
1958 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1959 32, nls_codepage);
1960 bcc_ptr += 2 * bytes_returned;
1961 bytes_returned =
1962 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
1963 nls_codepage);
1964 bcc_ptr += 2 * bytes_returned;
1965 bcc_ptr += 2;
1966 bytes_returned =
1967 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1968 64, nls_codepage);
1969 bcc_ptr += 2 * bytes_returned;
1970 bcc_ptr += 2;
1971 } else {
1972 strncpy(bcc_ptr, user, 200);
1973 bcc_ptr += strnlen(user, 200);
1974 *bcc_ptr = 0;
1975 bcc_ptr++;
1976 if (domain == NULL) {
1977 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1978 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1979 } else {
1980 strncpy(bcc_ptr, domain, 64);
1981 bcc_ptr += strnlen(domain, 64);
1982 *bcc_ptr = 0;
1983 bcc_ptr++;
1984 }
1985 strcpy(bcc_ptr, "Linux version ");
1986 bcc_ptr += strlen("Linux version ");
1987 strcpy(bcc_ptr, system_utsname.release);
1988 bcc_ptr += strlen(system_utsname.release) + 1;
1989 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1990 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1991 }
1992 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1993 smb_buffer->smb_buf_length += count;
1994 pSMB->req.ByteCount = cpu_to_le16(count);
1995
1996 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1997 &bytes_returned, 1);
1998 if (rc) {
1999/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2000 } else if ((smb_buffer_response->WordCount == 3)
2001 || (smb_buffer_response->WordCount == 4)) {
2002 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2003 __u16 blob_len =
2004 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2005 if (action & GUEST_LOGIN)
2006 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2007 if (ses) {
2008 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2009 cFYI(1, ("UID = %d ", ses->Suid));
2010 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2011
2012 /* BB Fix below to make endian neutral !! */
2013
2014 if ((pSMBr->resp.hdr.WordCount == 3)
2015 || ((pSMBr->resp.hdr.WordCount == 4)
2016 && (blob_len <
2017 pSMBr->resp.ByteCount))) {
2018 if (pSMBr->resp.hdr.WordCount == 4) {
2019 bcc_ptr +=
2020 blob_len;
2021 cFYI(1,
2022 ("Security Blob Length %d ",
2023 blob_len));
2024 }
2025
2026 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2027 if ((long) (bcc_ptr) % 2) {
2028 remaining_words =
2029 (BCC(smb_buffer_response)
2030 - 1) / 2;
2031 bcc_ptr++; /* Unicode strings must be word aligned */
2032 } else {
2033 remaining_words =
2034 BCC
2035 (smb_buffer_response) / 2;
2036 }
2037 len =
2038 UniStrnlen((wchar_t *) bcc_ptr,
2039 remaining_words - 1);
2040/* We look for obvious messed up bcc or strings in response so we do not go off
2041 the end since (at least) WIN2K and Windows XP have a major bug in not null
2042 terminating last Unicode string in response */
2043 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002044 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 cifs_strfromUCS_le(ses->serverOS,
2046 (wchar_t *)
2047 bcc_ptr, len,
2048 nls_codepage);
2049 bcc_ptr += 2 * (len + 1);
2050 remaining_words -= len + 1;
2051 ses->serverOS[2 * len] = 0;
2052 ses->serverOS[1 + (2 * len)] = 0;
2053 if (remaining_words > 0) {
2054 len = UniStrnlen((wchar_t *)bcc_ptr,
2055 remaining_words
2056 - 1);
2057 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002058 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 GFP_KERNEL);
2060 cifs_strfromUCS_le(ses->serverNOS,
2061 (wchar_t *)bcc_ptr,
2062 len,
2063 nls_codepage);
2064 bcc_ptr += 2 * (len + 1);
2065 ses->serverNOS[2 * len] = 0;
2066 ses->serverNOS[1 + (2 * len)] = 0;
2067 remaining_words -= len + 1;
2068 if (remaining_words > 0) {
2069 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2070 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002071 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 cifs_strfromUCS_le(ses->serverDomain,
2073 (wchar_t *)bcc_ptr,
2074 len,
2075 nls_codepage);
2076 bcc_ptr += 2*(len+1);
2077 ses->serverDomain[2*len] = 0;
2078 ses->serverDomain[1+(2*len)] = 0;
2079 } /* else no more room so create dummy domain string */
2080 else
2081 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002082 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002084 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2085 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 }
2087 } else { /* ASCII */
2088
2089 len = strnlen(bcc_ptr, 1024);
2090 if (((long) bcc_ptr + len) - (long)
2091 pByteArea(smb_buffer_response)
2092 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002093 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 strncpy(ses->serverOS, bcc_ptr, len);
2095
2096 bcc_ptr += len;
2097 bcc_ptr[0] = 0; /* null terminate the string */
2098 bcc_ptr++;
2099
2100 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002101 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 strncpy(ses->serverNOS, bcc_ptr, len);
2103 bcc_ptr += len;
2104 bcc_ptr[0] = 0;
2105 bcc_ptr++;
2106
2107 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002108 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 strncpy(ses->serverDomain, bcc_ptr, len);
2110 bcc_ptr += len;
2111 bcc_ptr[0] = 0;
2112 bcc_ptr++;
2113 } else
2114 cFYI(1,
2115 ("Variable field of length %d extends beyond end of smb ",
2116 len));
2117 }
2118 } else {
2119 cERROR(1,
2120 (" Security Blob Length extends beyond end of SMB"));
2121 }
2122 } else {
2123 cERROR(1, ("No session structure passed in."));
2124 }
2125 } else {
2126 cERROR(1,
2127 (" Invalid Word count %d: ",
2128 smb_buffer_response->WordCount));
2129 rc = -EIO;
2130 }
2131
2132 if (smb_buffer)
2133 cifs_buf_release(smb_buffer);
2134
2135 return rc;
2136}
2137
2138static int
2139CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2140 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2141 const struct nls_table *nls_codepage)
2142{
2143 struct smb_hdr *smb_buffer;
2144 struct smb_hdr *smb_buffer_response;
2145 SESSION_SETUP_ANDX *pSMB;
2146 SESSION_SETUP_ANDX *pSMBr;
2147 char *bcc_ptr;
2148 char *domain;
2149 int rc = 0;
2150 int remaining_words = 0;
2151 int bytes_returned = 0;
2152 int len;
2153 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2154 PNEGOTIATE_MESSAGE SecurityBlob;
2155 PCHALLENGE_MESSAGE SecurityBlob2;
2156 __u32 negotiate_flags, capabilities;
2157 __u16 count;
2158
2159 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2160 if(ses == NULL)
2161 return -EINVAL;
2162 domain = ses->domainName;
2163 *pNTLMv2_flag = FALSE;
2164 smb_buffer = cifs_buf_get();
2165 if (smb_buffer == NULL) {
2166 return -ENOMEM;
2167 }
2168 smb_buffer_response = smb_buffer;
2169 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2170 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2171
2172 /* send SMBsessionSetup here */
2173 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2174 NULL /* no tCon exists yet */ , 12 /* wct */ );
2175 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2176 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2177
2178 pSMB->req.AndXCommand = 0xFF;
2179 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2180 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2181
2182 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2183 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2184
2185 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2186 CAP_EXTENDED_SECURITY;
2187 if (ses->capabilities & CAP_UNICODE) {
2188 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2189 capabilities |= CAP_UNICODE;
2190 }
2191 if (ses->capabilities & CAP_STATUS32) {
2192 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2193 capabilities |= CAP_STATUS32;
2194 }
2195 if (ses->capabilities & CAP_DFS) {
2196 smb_buffer->Flags2 |= SMBFLG2_DFS;
2197 capabilities |= CAP_DFS;
2198 }
2199 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2200
2201 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2202 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2203 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2204 SecurityBlob->MessageType = NtLmNegotiate;
2205 negotiate_flags =
2206 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2207 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2208 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2209 if(sign_CIFS_PDUs)
2210 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2211 if(ntlmv2_support)
2212 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2213 /* setup pointers to domain name and workstation name */
2214 bcc_ptr += SecurityBlobLength;
2215
2216 SecurityBlob->WorkstationName.Buffer = 0;
2217 SecurityBlob->WorkstationName.Length = 0;
2218 SecurityBlob->WorkstationName.MaximumLength = 0;
2219
2220 if (domain == NULL) {
2221 SecurityBlob->DomainName.Buffer = 0;
2222 SecurityBlob->DomainName.Length = 0;
2223 SecurityBlob->DomainName.MaximumLength = 0;
2224 } else {
2225 __u16 len;
2226 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2227 strncpy(bcc_ptr, domain, 63);
2228 len = strnlen(domain, 64);
2229 SecurityBlob->DomainName.MaximumLength =
2230 cpu_to_le16(len);
2231 SecurityBlob->DomainName.Buffer =
2232 cpu_to_le32((long) &SecurityBlob->
2233 DomainString -
2234 (long) &SecurityBlob->Signature);
2235 bcc_ptr += len;
2236 SecurityBlobLength += len;
2237 SecurityBlob->DomainName.Length =
2238 cpu_to_le16(len);
2239 }
2240 if (ses->capabilities & CAP_UNICODE) {
2241 if ((long) bcc_ptr % 2) {
2242 *bcc_ptr = 0;
2243 bcc_ptr++;
2244 }
2245
2246 bytes_returned =
2247 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2248 32, nls_codepage);
2249 bcc_ptr += 2 * bytes_returned;
2250 bytes_returned =
2251 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2252 nls_codepage);
2253 bcc_ptr += 2 * bytes_returned;
2254 bcc_ptr += 2; /* null terminate Linux version */
2255 bytes_returned =
2256 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2257 64, nls_codepage);
2258 bcc_ptr += 2 * bytes_returned;
2259 *(bcc_ptr + 1) = 0;
2260 *(bcc_ptr + 2) = 0;
2261 bcc_ptr += 2; /* null terminate network opsys string */
2262 *(bcc_ptr + 1) = 0;
2263 *(bcc_ptr + 2) = 0;
2264 bcc_ptr += 2; /* null domain */
2265 } else { /* ASCII */
2266 strcpy(bcc_ptr, "Linux version ");
2267 bcc_ptr += strlen("Linux version ");
2268 strcpy(bcc_ptr, system_utsname.release);
2269 bcc_ptr += strlen(system_utsname.release) + 1;
2270 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2271 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2272 bcc_ptr++; /* empty domain field */
2273 *bcc_ptr = 0;
2274 }
2275 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2276 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2277 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2278 smb_buffer->smb_buf_length += count;
2279 pSMB->req.ByteCount = cpu_to_le16(count);
2280
2281 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2282 &bytes_returned, 1);
2283
2284 if (smb_buffer_response->Status.CifsError ==
2285 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2286 rc = 0;
2287
2288 if (rc) {
2289/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2290 } else if ((smb_buffer_response->WordCount == 3)
2291 || (smb_buffer_response->WordCount == 4)) {
2292 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2293 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2294
2295 if (action & GUEST_LOGIN)
2296 cFYI(1, (" Guest login"));
2297 /* Do we want to set anything in SesInfo struct when guest login? */
2298
2299 bcc_ptr = pByteArea(smb_buffer_response);
2300 /* response can have either 3 or 4 word count - Samba sends 3 */
2301
2302 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2303 if (SecurityBlob2->MessageType != NtLmChallenge) {
2304 cFYI(1,
2305 ("Unexpected NTLMSSP message type received %d",
2306 SecurityBlob2->MessageType));
2307 } else if (ses) {
2308 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2309 cFYI(1, ("UID = %d ", ses->Suid));
2310 if ((pSMBr->resp.hdr.WordCount == 3)
2311 || ((pSMBr->resp.hdr.WordCount == 4)
2312 && (blob_len <
2313 pSMBr->resp.ByteCount))) {
2314
2315 if (pSMBr->resp.hdr.WordCount == 4) {
2316 bcc_ptr += blob_len;
2317 cFYI(1,
2318 ("Security Blob Length %d ",
2319 blob_len));
2320 }
2321
2322 cFYI(1, ("NTLMSSP Challenge rcvd "));
2323
2324 memcpy(ses->server->cryptKey,
2325 SecurityBlob2->Challenge,
2326 CIFS_CRYPTO_KEY_SIZE);
2327 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2328 *pNTLMv2_flag = TRUE;
2329
2330 if((SecurityBlob2->NegotiateFlags &
2331 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2332 || (sign_CIFS_PDUs > 1))
2333 ses->server->secMode |=
2334 SECMODE_SIGN_REQUIRED;
2335 if ((SecurityBlob2->NegotiateFlags &
2336 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2337 ses->server->secMode |=
2338 SECMODE_SIGN_ENABLED;
2339
2340 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2341 if ((long) (bcc_ptr) % 2) {
2342 remaining_words =
2343 (BCC(smb_buffer_response)
2344 - 1) / 2;
2345 bcc_ptr++; /* Unicode strings must be word aligned */
2346 } else {
2347 remaining_words =
2348 BCC
2349 (smb_buffer_response) / 2;
2350 }
2351 len =
2352 UniStrnlen((wchar_t *) bcc_ptr,
2353 remaining_words - 1);
2354/* We look for obvious messed up bcc or strings in response so we do not go off
2355 the end since (at least) WIN2K and Windows XP have a major bug in not null
2356 terminating last Unicode string in response */
2357 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002358 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 cifs_strfromUCS_le(ses->serverOS,
2360 (wchar_t *)
2361 bcc_ptr, len,
2362 nls_codepage);
2363 bcc_ptr += 2 * (len + 1);
2364 remaining_words -= len + 1;
2365 ses->serverOS[2 * len] = 0;
2366 ses->serverOS[1 + (2 * len)] = 0;
2367 if (remaining_words > 0) {
2368 len = UniStrnlen((wchar_t *)
2369 bcc_ptr,
2370 remaining_words
2371 - 1);
2372 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002373 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 GFP_KERNEL);
2375 cifs_strfromUCS_le(ses->
2376 serverNOS,
2377 (wchar_t *)
2378 bcc_ptr,
2379 len,
2380 nls_codepage);
2381 bcc_ptr += 2 * (len + 1);
2382 ses->serverNOS[2 * len] = 0;
2383 ses->serverNOS[1 +
2384 (2 * len)] = 0;
2385 remaining_words -= len + 1;
2386 if (remaining_words > 0) {
2387 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2388 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2389 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002390 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 (len +
2392 1),
2393 GFP_KERNEL);
2394 cifs_strfromUCS_le
2395 (ses->
2396 serverDomain,
2397 (wchar_t *)
2398 bcc_ptr, len,
2399 nls_codepage);
2400 bcc_ptr +=
2401 2 * (len + 1);
2402 ses->
2403 serverDomain[2
2404 * len]
2405 = 0;
2406 ses->
2407 serverDomain[1
2408 +
2409 (2
2410 *
2411 len)]
2412 = 0;
2413 } /* else no more room so create dummy domain string */
2414 else
2415 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002416 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 GFP_KERNEL);
2418 } else { /* no room so create dummy domain and NOS string */
2419 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002420 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002422 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 }
2424 } else { /* ASCII */
2425 len = strnlen(bcc_ptr, 1024);
2426 if (((long) bcc_ptr + len) - (long)
2427 pByteArea(smb_buffer_response)
2428 <= BCC(smb_buffer_response)) {
2429 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002430 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 GFP_KERNEL);
2432 strncpy(ses->serverOS,
2433 bcc_ptr, len);
2434
2435 bcc_ptr += len;
2436 bcc_ptr[0] = 0; /* null terminate string */
2437 bcc_ptr++;
2438
2439 len = strnlen(bcc_ptr, 1024);
2440 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002441 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 GFP_KERNEL);
2443 strncpy(ses->serverNOS, bcc_ptr, len);
2444 bcc_ptr += len;
2445 bcc_ptr[0] = 0;
2446 bcc_ptr++;
2447
2448 len = strnlen(bcc_ptr, 1024);
2449 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002450 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 GFP_KERNEL);
2452 strncpy(ses->serverDomain, bcc_ptr, len);
2453 bcc_ptr += len;
2454 bcc_ptr[0] = 0;
2455 bcc_ptr++;
2456 } else
2457 cFYI(1,
2458 ("Variable field of length %d extends beyond end of smb ",
2459 len));
2460 }
2461 } else {
2462 cERROR(1,
2463 (" Security Blob Length extends beyond end of SMB"));
2464 }
2465 } else {
2466 cERROR(1, ("No session structure passed in."));
2467 }
2468 } else {
2469 cERROR(1,
2470 (" Invalid Word count %d: ",
2471 smb_buffer_response->WordCount));
2472 rc = -EIO;
2473 }
2474
2475 if (smb_buffer)
2476 cifs_buf_release(smb_buffer);
2477
2478 return rc;
2479}
2480static int
2481CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2482 char *ntlm_session_key, int ntlmv2_flag,
2483 const struct nls_table *nls_codepage)
2484{
2485 struct smb_hdr *smb_buffer;
2486 struct smb_hdr *smb_buffer_response;
2487 SESSION_SETUP_ANDX *pSMB;
2488 SESSION_SETUP_ANDX *pSMBr;
2489 char *bcc_ptr;
2490 char *user;
2491 char *domain;
2492 int rc = 0;
2493 int remaining_words = 0;
2494 int bytes_returned = 0;
2495 int len;
2496 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2497 PAUTHENTICATE_MESSAGE SecurityBlob;
2498 __u32 negotiate_flags, capabilities;
2499 __u16 count;
2500
2501 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2502 if(ses == NULL)
2503 return -EINVAL;
2504 user = ses->userName;
2505 domain = ses->domainName;
2506 smb_buffer = cifs_buf_get();
2507 if (smb_buffer == NULL) {
2508 return -ENOMEM;
2509 }
2510 smb_buffer_response = smb_buffer;
2511 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2512 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2513
2514 /* send SMBsessionSetup here */
2515 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2516 NULL /* no tCon exists yet */ , 12 /* wct */ );
2517 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2518 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2519 pSMB->req.AndXCommand = 0xFF;
2520 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2521 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2522
2523 pSMB->req.hdr.Uid = ses->Suid;
2524
2525 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2526 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2527
2528 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2529 CAP_EXTENDED_SECURITY;
2530 if (ses->capabilities & CAP_UNICODE) {
2531 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2532 capabilities |= CAP_UNICODE;
2533 }
2534 if (ses->capabilities & CAP_STATUS32) {
2535 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2536 capabilities |= CAP_STATUS32;
2537 }
2538 if (ses->capabilities & CAP_DFS) {
2539 smb_buffer->Flags2 |= SMBFLG2_DFS;
2540 capabilities |= CAP_DFS;
2541 }
2542 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2543
2544 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2545 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2546 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2547 SecurityBlob->MessageType = NtLmAuthenticate;
2548 bcc_ptr += SecurityBlobLength;
2549 negotiate_flags =
2550 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2551 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2552 0x80000000 | NTLMSSP_NEGOTIATE_128;
2553 if(sign_CIFS_PDUs)
2554 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2555 if(ntlmv2_flag)
2556 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2557
2558/* setup pointers to domain name and workstation name */
2559
2560 SecurityBlob->WorkstationName.Buffer = 0;
2561 SecurityBlob->WorkstationName.Length = 0;
2562 SecurityBlob->WorkstationName.MaximumLength = 0;
2563 SecurityBlob->SessionKey.Length = 0;
2564 SecurityBlob->SessionKey.MaximumLength = 0;
2565 SecurityBlob->SessionKey.Buffer = 0;
2566
2567 SecurityBlob->LmChallengeResponse.Length = 0;
2568 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2569 SecurityBlob->LmChallengeResponse.Buffer = 0;
2570
2571 SecurityBlob->NtChallengeResponse.Length =
2572 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2573 SecurityBlob->NtChallengeResponse.MaximumLength =
2574 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2575 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2576 SecurityBlob->NtChallengeResponse.Buffer =
2577 cpu_to_le32(SecurityBlobLength);
2578 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2579 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2580
2581 if (ses->capabilities & CAP_UNICODE) {
2582 if (domain == NULL) {
2583 SecurityBlob->DomainName.Buffer = 0;
2584 SecurityBlob->DomainName.Length = 0;
2585 SecurityBlob->DomainName.MaximumLength = 0;
2586 } else {
2587 __u16 len =
2588 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2589 nls_codepage);
2590 len *= 2;
2591 SecurityBlob->DomainName.MaximumLength =
2592 cpu_to_le16(len);
2593 SecurityBlob->DomainName.Buffer =
2594 cpu_to_le32(SecurityBlobLength);
2595 bcc_ptr += len;
2596 SecurityBlobLength += len;
2597 SecurityBlob->DomainName.Length =
2598 cpu_to_le16(len);
2599 }
2600 if (user == NULL) {
2601 SecurityBlob->UserName.Buffer = 0;
2602 SecurityBlob->UserName.Length = 0;
2603 SecurityBlob->UserName.MaximumLength = 0;
2604 } else {
2605 __u16 len =
2606 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2607 nls_codepage);
2608 len *= 2;
2609 SecurityBlob->UserName.MaximumLength =
2610 cpu_to_le16(len);
2611 SecurityBlob->UserName.Buffer =
2612 cpu_to_le32(SecurityBlobLength);
2613 bcc_ptr += len;
2614 SecurityBlobLength += len;
2615 SecurityBlob->UserName.Length =
2616 cpu_to_le16(len);
2617 }
2618
2619 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2620 SecurityBlob->WorkstationName.Length *= 2;
2621 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2622 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2623 bcc_ptr += SecurityBlob->WorkstationName.Length;
2624 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2625 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2626
2627 if ((long) bcc_ptr % 2) {
2628 *bcc_ptr = 0;
2629 bcc_ptr++;
2630 }
2631 bytes_returned =
2632 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2633 32, nls_codepage);
2634 bcc_ptr += 2 * bytes_returned;
2635 bytes_returned =
2636 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2637 nls_codepage);
2638 bcc_ptr += 2 * bytes_returned;
2639 bcc_ptr += 2; /* null term version string */
2640 bytes_returned =
2641 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2642 64, nls_codepage);
2643 bcc_ptr += 2 * bytes_returned;
2644 *(bcc_ptr + 1) = 0;
2645 *(bcc_ptr + 2) = 0;
2646 bcc_ptr += 2; /* null terminate network opsys string */
2647 *(bcc_ptr + 1) = 0;
2648 *(bcc_ptr + 2) = 0;
2649 bcc_ptr += 2; /* null domain */
2650 } else { /* ASCII */
2651 if (domain == NULL) {
2652 SecurityBlob->DomainName.Buffer = 0;
2653 SecurityBlob->DomainName.Length = 0;
2654 SecurityBlob->DomainName.MaximumLength = 0;
2655 } else {
2656 __u16 len;
2657 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2658 strncpy(bcc_ptr, domain, 63);
2659 len = strnlen(domain, 64);
2660 SecurityBlob->DomainName.MaximumLength =
2661 cpu_to_le16(len);
2662 SecurityBlob->DomainName.Buffer =
2663 cpu_to_le32(SecurityBlobLength);
2664 bcc_ptr += len;
2665 SecurityBlobLength += len;
2666 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2667 }
2668 if (user == NULL) {
2669 SecurityBlob->UserName.Buffer = 0;
2670 SecurityBlob->UserName.Length = 0;
2671 SecurityBlob->UserName.MaximumLength = 0;
2672 } else {
2673 __u16 len;
2674 strncpy(bcc_ptr, user, 63);
2675 len = strnlen(user, 64);
2676 SecurityBlob->UserName.MaximumLength =
2677 cpu_to_le16(len);
2678 SecurityBlob->UserName.Buffer =
2679 cpu_to_le32(SecurityBlobLength);
2680 bcc_ptr += len;
2681 SecurityBlobLength += len;
2682 SecurityBlob->UserName.Length = cpu_to_le16(len);
2683 }
2684 /* BB fill in our workstation name if known BB */
2685
2686 strcpy(bcc_ptr, "Linux version ");
2687 bcc_ptr += strlen("Linux version ");
2688 strcpy(bcc_ptr, system_utsname.release);
2689 bcc_ptr += strlen(system_utsname.release) + 1;
2690 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2691 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2692 bcc_ptr++; /* null domain */
2693 *bcc_ptr = 0;
2694 }
2695 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2696 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2697 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2698 smb_buffer->smb_buf_length += count;
2699 pSMB->req.ByteCount = cpu_to_le16(count);
2700
2701 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2702 &bytes_returned, 1);
2703 if (rc) {
2704/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2705 } else if ((smb_buffer_response->WordCount == 3)
2706 || (smb_buffer_response->WordCount == 4)) {
2707 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2708 __u16 blob_len =
2709 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2710 if (action & GUEST_LOGIN)
2711 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2712/* if(SecurityBlob2->MessageType != NtLm??){
2713 cFYI("Unexpected message type on auth response is %d "));
2714 } */
2715 if (ses) {
2716 cFYI(1,
2717 ("Does UID on challenge %d match auth response UID %d ",
2718 ses->Suid, smb_buffer_response->Uid));
2719 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2720 bcc_ptr = pByteArea(smb_buffer_response);
2721 /* response can have either 3 or 4 word count - Samba sends 3 */
2722 if ((pSMBr->resp.hdr.WordCount == 3)
2723 || ((pSMBr->resp.hdr.WordCount == 4)
2724 && (blob_len <
2725 pSMBr->resp.ByteCount))) {
2726 if (pSMBr->resp.hdr.WordCount == 4) {
2727 bcc_ptr +=
2728 blob_len;
2729 cFYI(1,
2730 ("Security Blob Length %d ",
2731 blob_len));
2732 }
2733
2734 cFYI(1,
2735 ("NTLMSSP response to Authenticate "));
2736
2737 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2738 if ((long) (bcc_ptr) % 2) {
2739 remaining_words =
2740 (BCC(smb_buffer_response)
2741 - 1) / 2;
2742 bcc_ptr++; /* Unicode strings must be word aligned */
2743 } else {
2744 remaining_words = BCC(smb_buffer_response) / 2;
2745 }
2746 len =
2747 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2748/* We look for obvious messed up bcc or strings in response so we do not go off
2749 the end since (at least) WIN2K and Windows XP have a major bug in not null
2750 terminating last Unicode string in response */
2751 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002752 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 cifs_strfromUCS_le(ses->serverOS,
2754 (wchar_t *)
2755 bcc_ptr, len,
2756 nls_codepage);
2757 bcc_ptr += 2 * (len + 1);
2758 remaining_words -= len + 1;
2759 ses->serverOS[2 * len] = 0;
2760 ses->serverOS[1 + (2 * len)] = 0;
2761 if (remaining_words > 0) {
2762 len = UniStrnlen((wchar_t *)
2763 bcc_ptr,
2764 remaining_words
2765 - 1);
2766 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002767 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 GFP_KERNEL);
2769 cifs_strfromUCS_le(ses->
2770 serverNOS,
2771 (wchar_t *)
2772 bcc_ptr,
2773 len,
2774 nls_codepage);
2775 bcc_ptr += 2 * (len + 1);
2776 ses->serverNOS[2 * len] = 0;
2777 ses->serverNOS[1+(2*len)] = 0;
2778 remaining_words -= len + 1;
2779 if (remaining_words > 0) {
2780 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2781 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2782 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002783 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 (len +
2785 1),
2786 GFP_KERNEL);
2787 cifs_strfromUCS_le
2788 (ses->
2789 serverDomain,
2790 (wchar_t *)
2791 bcc_ptr, len,
2792 nls_codepage);
2793 bcc_ptr +=
2794 2 * (len + 1);
2795 ses->
2796 serverDomain[2
2797 * len]
2798 = 0;
2799 ses->
2800 serverDomain[1
2801 +
2802 (2
2803 *
2804 len)]
2805 = 0;
2806 } /* else no more room so create dummy domain string */
2807 else
Steve French433dc242005-04-28 22:41:08 -07002808 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002810 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2811 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 }
2813 } else { /* ASCII */
2814 len = strnlen(bcc_ptr, 1024);
2815 if (((long) bcc_ptr + len) -
2816 (long) pByteArea(smb_buffer_response)
2817 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002818 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 strncpy(ses->serverOS,bcc_ptr, len);
2820
2821 bcc_ptr += len;
2822 bcc_ptr[0] = 0; /* null terminate the string */
2823 bcc_ptr++;
2824
2825 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002826 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 strncpy(ses->serverNOS, bcc_ptr, len);
2828 bcc_ptr += len;
2829 bcc_ptr[0] = 0;
2830 bcc_ptr++;
2831
2832 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002833 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 strncpy(ses->serverDomain, bcc_ptr, len);
2835 bcc_ptr += len;
2836 bcc_ptr[0] = 0;
2837 bcc_ptr++;
2838 } else
2839 cFYI(1,
2840 ("Variable field of length %d extends beyond end of smb ",
2841 len));
2842 }
2843 } else {
2844 cERROR(1,
2845 (" Security Blob Length extends beyond end of SMB"));
2846 }
2847 } else {
2848 cERROR(1, ("No session structure passed in."));
2849 }
2850 } else {
2851 cERROR(1,
2852 (" Invalid Word count %d: ",
2853 smb_buffer_response->WordCount));
2854 rc = -EIO;
2855 }
2856
2857 if (smb_buffer)
2858 cifs_buf_release(smb_buffer);
2859
2860 return rc;
2861}
2862
2863int
2864CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2865 const char *tree, struct cifsTconInfo *tcon,
2866 const struct nls_table *nls_codepage)
2867{
2868 struct smb_hdr *smb_buffer;
2869 struct smb_hdr *smb_buffer_response;
2870 TCONX_REQ *pSMB;
2871 TCONX_RSP *pSMBr;
2872 unsigned char *bcc_ptr;
2873 int rc = 0;
2874 int length;
2875 __u16 count;
2876
2877 if (ses == NULL)
2878 return -EIO;
2879
2880 smb_buffer = cifs_buf_get();
2881 if (smb_buffer == NULL) {
2882 return -ENOMEM;
2883 }
2884 smb_buffer_response = smb_buffer;
2885
2886 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2887 NULL /*no tid */ , 4 /*wct */ );
2888 smb_buffer->Uid = ses->Suid;
2889 pSMB = (TCONX_REQ *) smb_buffer;
2890 pSMBr = (TCONX_RSP *) smb_buffer_response;
2891
2892 pSMB->AndXCommand = 0xFF;
2893 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
2894 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
2895 bcc_ptr = &pSMB->Password[0];
2896 bcc_ptr++; /* skip password */
2897
2898 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2899 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2900
2901 if (ses->capabilities & CAP_STATUS32) {
2902 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2903 }
2904 if (ses->capabilities & CAP_DFS) {
2905 smb_buffer->Flags2 |= SMBFLG2_DFS;
2906 }
2907 if (ses->capabilities & CAP_UNICODE) {
2908 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2909 length =
2910 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
2911 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
2912 bcc_ptr += 2; /* skip trailing null */
2913 } else { /* ASCII */
2914
2915 strcpy(bcc_ptr, tree);
2916 bcc_ptr += strlen(tree) + 1;
2917 }
2918 strcpy(bcc_ptr, "?????");
2919 bcc_ptr += strlen("?????");
2920 bcc_ptr += 1;
2921 count = bcc_ptr - &pSMB->Password[0];
2922 pSMB->hdr.smb_buf_length += count;
2923 pSMB->ByteCount = cpu_to_le16(count);
2924
2925 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
2926
2927 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
2928 /* above now done in SendReceive */
2929 if ((rc == 0) && (tcon != NULL)) {
2930 tcon->tidStatus = CifsGood;
2931 tcon->tid = smb_buffer_response->Tid;
2932 bcc_ptr = pByteArea(smb_buffer_response);
2933 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
2934 /* skip service field (NB: this field is always ASCII) */
2935 bcc_ptr += length + 1;
2936 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
2937 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2938 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
2939 if ((bcc_ptr + (2 * length)) -
2940 pByteArea(smb_buffer_response) <=
2941 BCC(smb_buffer_response)) {
2942 if(tcon->nativeFileSystem)
2943 kfree(tcon->nativeFileSystem);
2944 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07002945 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 cifs_strfromUCS_le(tcon->nativeFileSystem,
2947 (wchar_t *) bcc_ptr,
2948 length, nls_codepage);
2949 bcc_ptr += 2 * length;
2950 bcc_ptr[0] = 0; /* null terminate the string */
2951 bcc_ptr[1] = 0;
2952 bcc_ptr += 2;
2953 }
2954 /* else do not bother copying these informational fields */
2955 } else {
2956 length = strnlen(bcc_ptr, 1024);
2957 if ((bcc_ptr + length) -
2958 pByteArea(smb_buffer_response) <=
2959 BCC(smb_buffer_response)) {
2960 if(tcon->nativeFileSystem)
2961 kfree(tcon->nativeFileSystem);
2962 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07002963 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 strncpy(tcon->nativeFileSystem, bcc_ptr,
2965 length);
2966 }
2967 /* else do not bother copying these informational fields */
2968 }
2969 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2970 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2971 } else if ((rc == 0) && tcon == NULL) {
2972 /* all we need to save for IPC$ connection */
2973 ses->ipc_tid = smb_buffer_response->Tid;
2974 }
2975
2976 if (smb_buffer)
2977 cifs_buf_release(smb_buffer);
2978 return rc;
2979}
2980
2981int
2982cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2983{
2984 int rc = 0;
2985 int xid;
2986 struct cifsSesInfo *ses = NULL;
2987 struct task_struct *cifsd_task;
2988
2989 xid = GetXid();
2990
2991 if (cifs_sb->tcon) {
2992 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
2993 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
2994 if (rc == -EBUSY) {
2995 FreeXid(xid);
2996 return 0;
2997 }
2998 tconInfoFree(cifs_sb->tcon);
2999 if ((ses) && (ses->server)) {
3000 /* save off task so we do not refer to ses later */
3001 cifsd_task = ses->server->tsk;
3002 cFYI(1, ("About to do SMBLogoff "));
3003 rc = CIFSSMBLogoff(xid, ses);
3004 if (rc == -EBUSY) {
3005 FreeXid(xid);
3006 return 0;
3007 } else if (rc == -ESHUTDOWN) {
3008 cFYI(1,("Waking up socket by sending it signal"));
3009 if(cifsd_task)
3010 send_sig(SIGKILL,cifsd_task,1);
3011 rc = 0;
3012 } /* else - we have an smb session
3013 left on this socket do not kill cifsd */
3014 } else
3015 cFYI(1, ("No session or bad tcon"));
3016 }
3017
3018 cifs_sb->tcon = NULL;
3019 if (ses) {
3020 set_current_state(TASK_INTERRUPTIBLE);
3021 schedule_timeout(HZ / 2);
3022 }
3023 if (ses)
3024 sesInfoFree(ses);
3025
3026 FreeXid(xid);
3027 return rc; /* BB check if we should always return zero here */
3028}
3029
3030int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3031 struct nls_table * nls_info)
3032{
3033 int rc = 0;
3034 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3035 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003036 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037
3038 /* what if server changes its buffer size after dropping the session? */
3039 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3040 rc = CIFSSMBNegotiate(xid, pSesInfo);
3041 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3042 rc = CIFSSMBNegotiate(xid, pSesInfo);
3043 if(rc == -EAGAIN)
3044 rc = -EHOSTDOWN;
3045 }
3046 if(rc == 0) {
3047 spin_lock(&GlobalMid_Lock);
3048 if(pSesInfo->server->tcpStatus != CifsExiting)
3049 pSesInfo->server->tcpStatus = CifsGood;
3050 else
3051 rc = -EHOSTDOWN;
3052 spin_unlock(&GlobalMid_Lock);
3053
3054 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003055 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 }
3057 if (!rc) {
3058 pSesInfo->capabilities = pSesInfo->server->capabilities;
3059 if(linuxExtEnabled == 0)
3060 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003061 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3063 pSesInfo->server->secMode,
3064 pSesInfo->server->capabilities,
3065 pSesInfo->server->timeZone));
3066 if (extended_security
3067 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3068 && (pSesInfo->server->secType == NTLMSSP)) {
3069 cFYI(1, ("New style sesssetup "));
3070 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3071 NULL /* security blob */,
3072 0 /* blob length */,
3073 nls_info);
3074 } else if (extended_security
3075 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3076 && (pSesInfo->server->secType == RawNTLMSSP)) {
3077 cFYI(1, ("NTLMSSP sesssetup "));
3078 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3079 pSesInfo,
3080 &ntlmv2_flag,
3081 nls_info);
3082 if (!rc) {
3083 if(ntlmv2_flag) {
3084 char * v2_response;
3085 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3086 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3087 nls_info)) {
3088 rc = -ENOMEM;
3089 goto ss_err_exit;
3090 } else
3091 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3092 if(v2_response) {
3093 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003094 /* if(first_time)
3095 cifs_calculate_ntlmv2_mac_key(
3096 pSesInfo->server->mac_signing_key,
3097 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 kfree(v2_response);
3099 /* BB Put dummy sig in SessSetup PDU? */
3100 } else {
3101 rc = -ENOMEM;
3102 goto ss_err_exit;
3103 }
3104
3105 } else {
3106 SMBNTencrypt(pSesInfo->password,
3107 pSesInfo->server->cryptKey,
3108 ntlm_session_key);
3109
Steve Frenchad009ac2005-04-28 22:41:05 -07003110 if(first_time)
3111 cifs_calculate_mac_key(
3112 pSesInfo->server->mac_signing_key,
3113 ntlm_session_key,
3114 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 }
3116 /* for better security the weaker lanman hash not sent
3117 in AuthSessSetup so we no longer calculate it */
3118
3119 rc = CIFSNTLMSSPAuthSessSetup(xid,
3120 pSesInfo,
3121 ntlm_session_key,
3122 ntlmv2_flag,
3123 nls_info);
3124 }
3125 } else { /* old style NTLM 0.12 session setup */
3126 SMBNTencrypt(pSesInfo->password,
3127 pSesInfo->server->cryptKey,
3128 ntlm_session_key);
3129
Steve Frenchad009ac2005-04-28 22:41:05 -07003130 if(first_time)
3131 cifs_calculate_mac_key(
3132 pSesInfo->server->mac_signing_key,
3133 ntlm_session_key, pSesInfo->password);
3134
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 rc = CIFSSessSetup(xid, pSesInfo,
3136 ntlm_session_key, nls_info);
3137 }
3138 if (rc) {
3139 cERROR(1,("Send error in SessSetup = %d",rc));
3140 } else {
3141 cFYI(1,("CIFS Session Established successfully"));
3142 pSesInfo->status = CifsGood;
3143 }
3144 }
3145ss_err_exit:
3146 return rc;
3147}
3148