blob: 4c13bcdb92a5f4800cbd9f1a1d8bb844e6844a5c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French366781c2008-01-25 10:12:41 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
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
Steve Frenchfb8c4b12007-07-10 01:16:18 +000019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21#include <linux/fs.h>
22#include <linux/net.h>
23#include <linux/string.h>
24#include <linux/list.h>
25#include <linux/wait.h>
26#include <linux/ipv6.h>
27#include <linux/pagemap.h>
28#include <linux/ctype.h>
29#include <linux/utsname.h>
30#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070031#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070032#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000033#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070034#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080035#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/uaccess.h>
37#include <asm/processor.h>
38#include "cifspdu.h"
39#include "cifsglob.h"
40#include "cifsproto.h"
41#include "cifs_unicode.h"
42#include "cifs_debug.h"
43#include "cifs_fs_sb.h"
44#include "ntlmssp.h"
45#include "nterr.h"
46#include "rfc1002pdu.h"
Steve Frencha2653eb2005-11-10 15:33:38 -080047#include "cn_cifs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define CIFS_PORT 445
50#define RFC1001_PORT 139
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
53 unsigned char *p24);
54
55extern mempool_t *cifs_req_poolp;
56
57struct smb_vol {
58 char *username;
59 char *password;
60 char *domainname;
61 char *UNC;
62 char *UNCip;
Steve French95b1cb92008-05-15 16:44:38 +000063 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 char *iocharset; /* local code page for mapping to and from Unicode */
65 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070066 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 uid_t linux_uid;
68 gid_t linux_gid;
69 mode_t file_mode;
70 mode_t dir_mode;
Steve French189acaa2006-06-23 02:33:48 +000071 unsigned secFlg;
Steve French4b18f2a2008-04-29 00:06:05 +000072 bool rw:1;
73 bool retry:1;
74 bool intr:1;
75 bool setuids:1;
76 bool override_uid:1;
77 bool override_gid:1;
Jeff Laytond0a9c072008-05-12 22:23:49 +000078 bool dynperm:1;
Steve French4b18f2a2008-04-29 00:06:05 +000079 bool noperm:1;
80 bool no_psx_acl:1; /* set if posix acl support should be disabled */
81 bool cifs_acl:1;
82 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
83 bool server_ino:1; /* use inode numbers from server ie UniqueId */
84 bool direct_io:1;
Steve French95b1cb92008-05-15 16:44:38 +000085 bool remap:1; /* set to remap seven reserved chars in filenames */
86 bool posix_paths:1; /* unset to not ask for posix pathnames. */
Steve French4b18f2a2008-04-29 00:06:05 +000087 bool no_linux_ext:1;
88 bool sfu_emul:1;
Steve French95b1cb92008-05-15 16:44:38 +000089 bool nullauth:1; /* attempt to authenticate with null user */
90 bool nocase:1; /* request case insensitive filenames */
91 bool nobrl:1; /* disable sending byte range locks to srv */
92 bool seal:1; /* request transport encryption on share */
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 unsigned int rsize;
94 unsigned int wsize;
95 unsigned int sockopt;
96 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000097 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098};
99
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000100static int ipv4_connect(struct sockaddr_in *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 struct socket **csocket,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000102 char *netb_name,
103 char *server_netb_name);
104static int ipv6_connect(struct sockaddr_in6 *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 struct socket **csocket);
106
107
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000108 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000110 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 * mark tcp session as reconnecting so temporarily locked
112 * mark all smb sessions as reconnecting for tcp session
113 * reconnect tcp session
114 * wake up waiters on reconnection? - (not needed currently)
115 */
116
Steve French2cd646a2006-09-28 19:43:08 +0000117static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118cifs_reconnect(struct TCP_Server_Info *server)
119{
120 int rc = 0;
121 struct list_head *tmp;
122 struct cifsSesInfo *ses;
123 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000124 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000127 if (kthread_should_stop()) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000128 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 next time through the loop */
130 spin_unlock(&GlobalMid_Lock);
131 return rc;
132 } else
133 server->tcpStatus = CifsNeedReconnect;
134 spin_unlock(&GlobalMid_Lock);
135 server->maxBuf = 0;
136
Steve Frenche4eb2952005-04-28 22:41:09 -0700137 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139 /* before reconnecting the tcp session, mark the smb session (uid)
140 and the tid bad so they are not used until reconnected */
141 read_lock(&GlobalSMBSeslock);
142 list_for_each(tmp, &GlobalSMBSessionList) {
143 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
144 if (ses->server) {
145 if (ses->server == server) {
146 ses->status = CifsNeedReconnect;
147 ses->ipc_tid = 0;
148 }
149 }
150 /* else tcp and smb sessions need reconnection */
151 }
152 list_for_each(tmp, &GlobalTreeConnectionList) {
153 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000154 if ((tcon->ses) && (tcon->ses->server == server))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 tcon->tidStatus = CifsNeedReconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 }
157 read_unlock(&GlobalSMBSeslock);
158 /* do not want to be sending data on a socket we are freeing */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000159 down(&server->tcpSem);
160 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000161 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800163 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000164 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000165 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 server->ssocket->flags));
167 sock_release(server->ssocket);
168 server->ssocket = NULL;
169 }
170
171 spin_lock(&GlobalMid_Lock);
172 list_for_each(tmp, &server->pending_mid_q) {
173 mid_entry = list_entry(tmp, struct
174 mid_q_entry,
175 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000176 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700177 /* Mark other intransit requests as needing
178 retry so we do not immediately mark the
179 session bad again (ie after we reconnect
180 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000181 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 }
183 }
184 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000185 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Steve French26f57362007-08-30 22:09:15 +0000187 while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000188 try_to_freeze();
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000189 if (server->protocolType == IPV6) {
190 rc = ipv6_connect(&server->addr.sockAddr6,
191 &server->ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000193 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700195 server->workstation_RFC1001_name,
196 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000198 if (rc) {
199 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700200 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 } else {
202 atomic_inc(&tcpSesReconnectCount);
203 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000204 if (!kthread_should_stop())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700206 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000207 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 /* atomic_set(&server->inFlight,0);*/
209 wake_up(&server->response_q);
210 }
211 }
212 return rc;
213}
214
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000215/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700216 return codes:
217 0 not a transact2, or all data present
218 >0 transact2 with that much data missing
219 -EINVAL = invalid transact2
220
221 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000222static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700223{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000224 struct smb_t2_rsp *pSMBt;
225 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700226 int data_in_this_rsp;
227 int remaining;
228
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000229 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700230 return 0;
231
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000232 /* check for plausible wct, bcc and t2 data and parm sizes */
233 /* check for parm and data offset going beyond end of smb */
234 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000235 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700236 return -EINVAL;
237 }
238
239 pSMBt = (struct smb_t2_rsp *)pSMB;
240
241 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
242 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
243
244 remaining = total_data_size - data_in_this_rsp;
245
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000246 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700247 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000248 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000249 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700250 total_data_size, data_in_this_rsp));
251 return -EINVAL;
252 } else {
Steve French467a8f82007-06-27 22:41:32 +0000253 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700254 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000255 if (total_data_size > maxBufSize) {
256 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
257 total_data_size, maxBufSize));
258 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700259 }
260 return remaining;
261 }
262}
263
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000264static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700265{
266 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
267 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
268 int total_data_size;
269 int total_in_buf;
270 int remaining;
271 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000272 char *data_area_of_target;
273 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700274 __u16 byte_count;
275
276 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
277
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000278 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000279 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700280 }
281
282 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
283
284 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000285
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000286 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700287 return -EINVAL;
288
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000289 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700290 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000291
Steve Frenche4eb2952005-04-28 22:41:09 -0700292 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000293 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000294 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700295 }
296
297 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000298 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700299 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
300 /* validate target area */
301
302 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000303 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700304
305 data_area_of_target += total_in_buf;
306
307 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000308 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700309 total_in_buf += total_in_buf2;
310 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
311 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
312 byte_count += total_in_buf2;
313 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
314
Steve French70ca7342005-09-22 16:32:06 -0700315 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700316 byte_count += total_in_buf2;
317
318 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000319
Steve French70ca7342005-09-22 16:32:06 -0700320 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700321
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000322 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000323 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700324 return 0; /* we are done */
325 } else /* more responses to go */
326 return 1;
327
328}
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330static int
331cifs_demultiplex_thread(struct TCP_Server_Info *server)
332{
333 int length;
334 unsigned int pdu_length, total_read;
335 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700336 struct smb_hdr *bigbuf = NULL;
337 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 struct msghdr smb_msg;
339 struct kvec iov;
340 struct socket *csocket = server->ssocket;
341 struct list_head *tmp;
342 struct cifsSesInfo *ses;
343 struct task_struct *task_to_wake = NULL;
344 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700345 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000346 bool isLargeBuf = false;
347 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700348 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700351 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400352
353 length = atomic_inc_return(&tcpSesAllocCount);
354 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000355 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
356 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700358 set_freezable();
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000359 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700360 if (try_to_freeze())
361 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700362 if (bigbuf == NULL) {
363 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000364 if (!bigbuf) {
365 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700366 msleep(3000);
367 /* retry will check if exiting */
368 continue;
369 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000370 } else if (isLargeBuf) {
371 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000372 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700374
375 if (smallbuf == NULL) {
376 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000377 if (!smallbuf) {
378 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700379 msleep(1000);
380 /* retry will check if exiting */
381 continue;
382 }
383 /* beginning of smb buffer is cleared in our buf_get */
384 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000385 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700386
Steve French4b18f2a2008-04-29 00:06:05 +0000387 isLargeBuf = false;
388 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700389 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 iov.iov_base = smb_buffer;
391 iov.iov_len = 4;
392 smb_msg.msg_control = NULL;
393 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000394 pdu_length = 4; /* enough to get RFC1001 header */
395incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 length =
397 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000398 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Steve French26f57362007-08-30 22:09:15 +0000400 if (kthread_should_stop()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 break;
402 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000403 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000405 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 csocket = server->ssocket;
407 continue;
408 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700409 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 allowing socket to clear and app threads to set
411 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc18c7322007-10-17 18:01:11 +0000412 if (pdu_length < 4)
413 goto incomplete_rcv;
414 else
415 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000417 if (server->tcpStatus == CifsNew) {
418 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700419 /* some servers kill the TCP session rather than
420 returning an SMB negprot error, in which
421 case reconnecting here is not going to help,
422 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 break;
424 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000425 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000426 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 break;
428 }
Steve French467a8f82007-06-27 22:41:32 +0000429 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700430 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 cifs_reconnect(server);
432 csocket = server->ssocket;
433 wake_up(&server->response_q);
434 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000435 } else if (length < pdu_length) {
436 cFYI(1, ("requested %d bytes but only got %d bytes",
437 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000438 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000439 msleep(1);
440 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 }
Steve French67010fb2005-04-28 22:41:09 -0700442
Steve French70ca7342005-09-22 16:32:06 -0700443 /* The right amount was read from socket - 4 bytes */
444 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700445
Steve French70ca7342005-09-22 16:32:06 -0700446 /* the first byte big endian of the length field,
447 is actually not part of the length but the type
448 with the most common, zero, as regular data */
449 temp = *((char *) smb_buffer);
450
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000451 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700452 but we convert it here so it is always manipulated
453 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700454 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700455 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700456
Steve French467a8f82007-06-27 22:41:32 +0000457 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700458
459 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000460 continue;
Steve French70ca7342005-09-22 16:32:06 -0700461 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000462 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700463 continue;
Steve French70ca7342005-09-22 16:32:06 -0700464 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000465 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700466 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000467 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700468 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000469 if (server->tcpStatus == CifsNew) {
470 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700471 ret of smb negprot error) reconnecting
472 not going to help, ret error to mount */
473 break;
474 } else {
475 /* give server a second to
476 clean up before reconnect attempt */
477 msleep(1000);
478 /* always try 445 first on reconnect
479 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000480 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700481 since we do not begin with RFC1001
482 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000483 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700484 htons(CIFS_PORT);
485 cifs_reconnect(server);
486 csocket = server->ssocket;
487 wake_up(&server->response_q);
488 continue;
489 }
Steve French70ca7342005-09-22 16:32:06 -0700490 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000491 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700492 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
493 length);
Steve French46810cb2005-04-28 22:41:09 -0700494 cifs_reconnect(server);
495 csocket = server->ssocket;
496 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700497 }
498
499 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000500 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000501 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700502 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700503 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700504 cifs_reconnect(server);
505 csocket = server->ssocket;
506 wake_up(&server->response_q);
507 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000508 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700509
510 /* else length ok */
511 reconnect = 0;
512
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000513 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000514 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700515 memcpy(bigbuf, smallbuf, 4);
516 smb_buffer = bigbuf;
517 }
518 length = 0;
519 iov.iov_base = 4 + (char *)smb_buffer;
520 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000521 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700522 total_read += length) {
523 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
524 pdu_length - total_read, 0);
Steve French26f57362007-08-30 22:09:15 +0000525 if (kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700526 (length == -EINTR)) {
527 /* then will exit */
528 reconnect = 2;
529 break;
530 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700531 cifs_reconnect(server);
532 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000533 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700534 /* Now we will reread sock */
535 reconnect = 1;
536 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000537 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700538 (length == -EAGAIN)) {
539 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 threads to set tcpStatus
542 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000543 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700544 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700545 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000546 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 pdu_length - total_read));
548 cifs_reconnect(server);
549 csocket = server->ssocket;
550 reconnect = 1;
551 break;
Steve French46810cb2005-04-28 22:41:09 -0700552 }
553 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000554 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700555 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000556 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700557 continue;
558
559 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000560
Steve Frenche4eb2952005-04-28 22:41:09 -0700561
562 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000563 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700564 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700565 continue;
566 }
567
568
569 task_to_wake = NULL;
570 spin_lock(&GlobalMid_Lock);
571 list_for_each(tmp, &server->pending_mid_q) {
572 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
573
Steve French50c2f752007-07-13 00:33:32 +0000574 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700575 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
576 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000577 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000579 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000580 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000582 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000584 mid_entry->multiRsp =
585 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 break;
587 } else {
588 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000589 mid_entry->multiEnd =
590 true;
Steve French50c2f752007-07-13 00:33:32 +0000591 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700592 }
593 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000594 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 cERROR(1,("1st trans2 resp needs bigbuf"));
596 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000597 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700599 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700600 mid_entry->resp_buf =
601 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000602 mid_entry->largeBuf =
603 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700604 bigbuf = NULL;
605 }
606 }
607 break;
Steve French50c2f752007-07-13 00:33:32 +0000608 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700609 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000610 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700611multi_t2_fnd:
612 task_to_wake = mid_entry->tsk;
613 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700614#ifdef CONFIG_CIFS_STATS2
615 mid_entry->when_received = jiffies;
616#endif
Steve French3a5ff612006-07-14 22:37:11 +0000617 /* so we do not time out requests to server
618 which is still responding (since server could
619 be busy but not dead) */
620 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700621 break;
622 }
623 }
624 spin_unlock(&GlobalMid_Lock);
625 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700626 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000627 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700628 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000629 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700630 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000631 else
Steve Frenchcd634992005-04-28 22:41:10 -0700632 smallbuf = NULL;
633 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700634 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000635 } else if (!is_valid_oplock_break(smb_buffer, server) &&
636 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000637 cERROR(1, ("No task to wake, unknown frame received! "
638 "NumMids %d", midCount.counter));
639 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700640 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000641#ifdef CONFIG_CIFS_DEBUG2
642 cifs_dump_detail(smb_buffer);
643 cifs_dump_mids(server);
644#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000645
Steve Frenche4eb2952005-04-28 22:41:09 -0700646 }
647 } /* end while !EXITING */
648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 spin_lock(&GlobalMid_Lock);
650 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000651 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000652 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000653
654 /* don't exit until kthread_stop is called */
655 set_current_state(TASK_UNINTERRUPTIBLE);
656 while (!kthread_should_stop()) {
657 schedule();
658 set_current_state(TASK_UNINTERRUPTIBLE);
659 }
660 set_current_state(TASK_RUNNING);
661
Steve French31ca3bc2005-04-28 22:41:11 -0700662 /* check if we have blocked requests that need to free */
663 /* Note that cifs_max_pending is normally 50, but
664 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000665 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000666 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700667 atomic_set(&server->inFlight, cifs_max_pending - 1);
668 /* We do not want to set the max_pending too low or we
669 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000671 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700673 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 to the same server - they now will see the session is in exit state
675 and get out of SendReceive. */
676 wake_up_all(&server->request_q);
677 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700678 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000679
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000680 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 sock_release(csocket);
682 server->ssocket = NULL;
683 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700684 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000685 cifs_buf_release(bigbuf);
686 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700687 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 read_lock(&GlobalSMBSeslock);
690 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700691 /* loop through server session structures attached to this and
692 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 list_for_each(tmp, &GlobalSMBSessionList) {
694 ses =
695 list_entry(tmp, struct cifsSesInfo,
696 cifsSessionList);
697 if (ses->server == server) {
698 ses->status = CifsExiting;
699 ses->server = NULL;
700 }
701 }
702 read_unlock(&GlobalSMBSeslock);
703 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700704 /* although we can not zero the server struct pointer yet,
705 since there are active requests which may depnd on them,
706 mark the corresponding SMB sessions as exiting too */
707 list_for_each(tmp, &GlobalSMBSessionList) {
708 ses = list_entry(tmp, struct cifsSesInfo,
709 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000710 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700711 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700712 }
713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 spin_lock(&GlobalMid_Lock);
715 list_for_each(tmp, &server->pending_mid_q) {
716 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
717 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000718 cFYI(1, ("Clearing Mid 0x%x - waking up ",
719 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000721 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724 }
725 spin_unlock(&GlobalMid_Lock);
726 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700728 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730
Steve Frenchf1914012005-08-18 09:37:34 -0700731 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000732 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700734 /* due to delays on oplock break requests, we need
735 to wait at least 45 seconds before giving up
736 on a request getting a response and going ahead
737 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700739 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 /* if threads still have not exited they are probably never
741 coming home not much else we can do but free the memory */
742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Steve French31ca3bc2005-04-28 22:41:11 -0700744 /* last chance to mark ses pointers invalid
745 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000746 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700747 kernel thread explicitly this might happen) */
Jeff Layton93d0ec82008-08-02 08:00:48 -0400748 write_lock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700749 list_for_each(tmp, &GlobalSMBSessionList) {
750 ses = list_entry(tmp, struct cifsSesInfo,
751 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000752 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700753 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700756
Jeff Laytonc359cf32007-11-16 22:22:06 +0000757 kfree(server->hostname);
Steve French31ca3bc2005-04-28 22:41:11 -0700758 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400759
760 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000761 if (length > 0)
762 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
763 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return 0;
766}
767
Jeff Laytonc359cf32007-11-16 22:22:06 +0000768/* extract the host portion of the UNC string */
769static char *
770extract_hostname(const char *unc)
771{
772 const char *src;
773 char *dst, *delim;
774 unsigned int len;
775
776 /* skip double chars at beginning of string */
777 /* BB: check validity of these bytes? */
778 src = unc + 2;
779
780 /* delimiter between hostname and sharename is always '\\' now */
781 delim = strchr(src, '\\');
782 if (!delim)
783 return ERR_PTR(-EINVAL);
784
785 len = delim - src;
786 dst = kmalloc((len + 1), GFP_KERNEL);
787 if (dst == NULL)
788 return ERR_PTR(-ENOMEM);
789
790 memcpy(dst, src, len);
791 dst[len] = '\0';
792
793 return dst;
794}
795
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796static int
Steve French50c2f752007-07-13 00:33:32 +0000797cifs_parse_mount_options(char *options, const char *devname,
798 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799{
800 char *value;
801 char *data;
802 unsigned int temp_len, i, j;
803 char separator[2];
804
805 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000806 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Linus Torvalds12e36b22006-10-13 08:09:29 -0700808 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000809 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000810 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700811 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000812 int n = strnlen(nodename, 15);
813 memset(vol->source_rfc1001_name, 0x20, 15);
814 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000815 /* does not have to be perfect mapping since field is
816 informational, only used for servers that do not support
817 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700818 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
821 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700822 /* null target name indicates to use *SMBSERVR default called name
823 if we end up sending RFC1001 session initialize */
824 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 vol->linux_uid = current->uid; /* current->euid instead? */
826 vol->linux_gid = current->gid;
827 vol->dir_mode = S_IRWXUGO;
828 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000829 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000832 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700833 /* default is always to request posix paths. */
834 vol->posix_paths = 1;
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (!options)
837 return 1;
838
Steve French50c2f752007-07-13 00:33:32 +0000839 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000840 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 separator[0] = options[4];
842 options += 5;
843 } else {
Steve French467a8f82007-06-27 22:41:32 +0000844 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 }
846 }
Steve French50c2f752007-07-13 00:33:32 +0000847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 while ((data = strsep(&options, separator)) != NULL) {
849 if (!*data)
850 continue;
851 if ((value = strchr(data, '=')) != NULL)
852 *value++ = '\0';
853
Steve French50c2f752007-07-13 00:33:32 +0000854 /* Have to parse this before we parse for "user" */
855 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000857 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 vol->no_xattr = 1;
859 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000860 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 printk(KERN_WARNING
862 "CIFS: invalid or missing username\n");
863 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000864 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000865 /* null user, ie anonymous, authentication */
866 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 }
868 if (strnlen(value, 200) < 200) {
869 vol->username = value;
870 } else {
871 printk(KERN_WARNING "CIFS: username too long\n");
872 return 1;
873 }
874 } else if (strnicmp(data, "pass", 4) == 0) {
875 if (!value) {
876 vol->password = NULL;
877 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000878 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 /* check if string begins with double comma
880 since that would mean the password really
881 does start with a comma, and would not
882 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000883 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 vol->password = NULL;
885 continue;
886 }
887 }
888 temp_len = strlen(value);
889 /* removed password length check, NTLM passwords
890 can be arbitrarily long */
891
Steve French50c2f752007-07-13 00:33:32 +0000892 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 prematurely null terminated. Commas in password are
894 specified across the cifs mount interface by a double
895 comma ie ,, and a comma used as in other cases ie ','
896 as a parameter delimiter/separator is single and due
897 to the strsep above is temporarily zeroed. */
898
899 /* NB: password legally can have multiple commas and
900 the only illegal character in a password is null */
901
Steve French50c2f752007-07-13 00:33:32 +0000902 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700903 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 /* reinsert comma */
905 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000906 temp_len += 2; /* move after second comma */
907 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000909 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700910 separator[0]) {
911 /* skip second comma */
912 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000913 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 /* single comma indicating start
915 of next parm */
916 break;
917 }
918 }
919 temp_len++;
920 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000921 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 options = NULL;
923 } else {
924 value[temp_len] = 0;
925 /* point option to start of next parm */
926 options = value + temp_len + 1;
927 }
Steve French50c2f752007-07-13 00:33:32 +0000928 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 double commas to singles. Note that this ends up
930 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700931 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000932 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000933 printk(KERN_WARNING "CIFS: no memory "
934 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700935 return 1;
936 }
Steve French50c2f752007-07-13 00:33:32 +0000937 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000939 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700940 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 /* skip second comma */
942 i++;
943 }
944 }
945 vol->password[j] = 0;
946 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700947 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000948 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000949 printk(KERN_WARNING "CIFS: no memory "
950 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700951 return 1;
952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 strcpy(vol->password, value);
954 }
955 } else if (strnicmp(data, "ip", 2) == 0) {
956 if (!value || !*value) {
957 vol->UNCip = NULL;
958 } else if (strnlen(value, 35) < 35) {
959 vol->UNCip = value;
960 } else {
Steve French50c2f752007-07-13 00:33:32 +0000961 printk(KERN_WARNING "CIFS: ip address "
962 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 return 1;
964 }
Steve French50c2f752007-07-13 00:33:32 +0000965 } else if (strnicmp(data, "sec", 3) == 0) {
966 if (!value || !*value) {
967 cERROR(1, ("no security value specified"));
968 continue;
969 } else if (strnicmp(value, "krb5i", 5) == 0) {
970 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000971 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800972 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000973 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
974 CIFSSEC_MAY_KRB5; */
975 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800976 return 1;
977 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000978 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800979 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000980 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000981 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800982 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000983 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800984 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000985 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000986 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800987 } else if (strnicmp(value, "ntlm", 4) == 0) {
988 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000989 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800990 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000991 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000992 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000993#ifdef CONFIG_CIFS_WEAK_PW_HASH
994 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000995 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000996#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800997 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000998 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000999 } else {
1000 cERROR(1, ("bad security option: %s", value));
1001 return 1;
1002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 } else if ((strnicmp(data, "unc", 3) == 0)
1004 || (strnicmp(data, "target", 6) == 0)
1005 || (strnicmp(data, "path", 4) == 0)) {
1006 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001007 printk(KERN_WARNING "CIFS: invalid path to "
1008 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return 1; /* needs_arg; */
1010 }
1011 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001012 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001013 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001015 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 if (strncmp(vol->UNC, "//", 2) == 0) {
1017 vol->UNC[0] = '\\';
1018 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001019 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001021 "CIFS: UNC Path does not begin "
1022 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 return 1;
1024 }
1025 } else {
1026 printk(KERN_WARNING "CIFS: UNC name too long\n");
1027 return 1;
1028 }
1029 } else if ((strnicmp(data, "domain", 3) == 0)
1030 || (strnicmp(data, "workgroup", 5) == 0)) {
1031 if (!value || !*value) {
1032 printk(KERN_WARNING "CIFS: invalid domain name\n");
1033 return 1; /* needs_arg; */
1034 }
1035 /* BB are there cases in which a comma can be valid in
1036 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001037 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 vol->domainname = value;
1039 cFYI(1, ("Domain name set"));
1040 } else {
Steve French50c2f752007-07-13 00:33:32 +00001041 printk(KERN_WARNING "CIFS: domain name too "
1042 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 return 1;
1044 }
Steve French50c2f752007-07-13 00:33:32 +00001045 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1046 if (!value || !*value) {
1047 printk(KERN_WARNING
1048 "CIFS: invalid path prefix\n");
1049 return 1; /* needs_argument */
1050 }
1051 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001052 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001053 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001054 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1055 if (vol->prepath == NULL)
1056 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001057 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001058 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001059 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001060 } else
Steve French50c2f752007-07-13 00:33:32 +00001061 strcpy(vol->prepath, value);
1062 cFYI(1, ("prefix path %s", vol->prepath));
1063 } else {
1064 printk(KERN_WARNING "CIFS: prefix too long\n");
1065 return 1;
1066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 } else if (strnicmp(data, "iocharset", 9) == 0) {
1068 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001069 printk(KERN_WARNING "CIFS: invalid iocharset "
1070 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return 1; /* needs_arg; */
1072 }
1073 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001074 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001076 /* if iocharset not set then load_nls_default
1077 is used by caller */
1078 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 } else {
Steve French63135e02007-07-17 17:34:02 +00001080 printk(KERN_WARNING "CIFS: iocharset name "
1081 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 return 1;
1083 }
1084 } else if (strnicmp(data, "uid", 3) == 0) {
1085 if (value && *value) {
1086 vol->linux_uid =
1087 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001088 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 }
1090 } else if (strnicmp(data, "gid", 3) == 0) {
1091 if (value && *value) {
1092 vol->linux_gid =
1093 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001094 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096 } else if (strnicmp(data, "file_mode", 4) == 0) {
1097 if (value && *value) {
1098 vol->file_mode =
1099 simple_strtoul(value, &value, 0);
1100 }
1101 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1102 if (value && *value) {
1103 vol->dir_mode =
1104 simple_strtoul(value, &value, 0);
1105 }
1106 } else if (strnicmp(data, "dirmode", 4) == 0) {
1107 if (value && *value) {
1108 vol->dir_mode =
1109 simple_strtoul(value, &value, 0);
1110 }
1111 } else if (strnicmp(data, "port", 4) == 0) {
1112 if (value && *value) {
1113 vol->port =
1114 simple_strtoul(value, &value, 0);
1115 }
1116 } else if (strnicmp(data, "rsize", 5) == 0) {
1117 if (value && *value) {
1118 vol->rsize =
1119 simple_strtoul(value, &value, 0);
1120 }
1121 } else if (strnicmp(data, "wsize", 5) == 0) {
1122 if (value && *value) {
1123 vol->wsize =
1124 simple_strtoul(value, &value, 0);
1125 }
1126 } else if (strnicmp(data, "sockopt", 5) == 0) {
1127 if (value && *value) {
1128 vol->sockopt =
1129 simple_strtoul(value, &value, 0);
1130 }
1131 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1132 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001133 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 } else {
Steve French50c2f752007-07-13 00:33:32 +00001135 memset(vol->source_rfc1001_name, 0x20, 15);
1136 for (i = 0; i < 15; i++) {
1137 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 valid in this workstation netbios name (and need
1139 special handling)? */
1140
1141 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001142 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 break;
Steve French50c2f752007-07-13 00:33:32 +00001144 else
1145 vol->source_rfc1001_name[i] =
1146 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148 /* The string has 16th byte zero still from
1149 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001150 if ((i == 15) && (value[i] != 0))
1151 printk(KERN_WARNING "CIFS: netbiosname"
1152 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001153 }
1154 } else if (strnicmp(data, "servern", 7) == 0) {
1155 /* servernetbiosname specified override *SMBSERVER */
1156 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001157 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001158 } else {
1159 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001160 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001161
Steve French50c2f752007-07-13 00:33:32 +00001162 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001163 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001164 valid in this workstation netbios name
1165 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001166
Steve French50c2f752007-07-13 00:33:32 +00001167 /* user or mount helper must uppercase
1168 the netbiosname */
1169 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001170 break;
1171 else
Steve French50c2f752007-07-13 00:33:32 +00001172 vol->target_rfc1001_name[i] =
1173 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001174 }
1175 /* The string has 16th byte zero still from
1176 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001177 if ((i == 15) && (value[i] != 0))
1178 printk(KERN_WARNING "CIFS: server net"
1179 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
1181 } else if (strnicmp(data, "credentials", 4) == 0) {
1182 /* ignore */
1183 } else if (strnicmp(data, "version", 3) == 0) {
1184 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001185 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 /* ignore */
1187 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001188 vol->rw = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 } else if ((strnicmp(data, "suid", 4) == 0) ||
1190 (strnicmp(data, "nosuid", 6) == 0) ||
1191 (strnicmp(data, "exec", 4) == 0) ||
1192 (strnicmp(data, "noexec", 6) == 0) ||
1193 (strnicmp(data, "nodev", 5) == 0) ||
1194 (strnicmp(data, "noauto", 6) == 0) ||
1195 (strnicmp(data, "dev", 3) == 0)) {
1196 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001197 uses these opts to set flags, and the flags are read
1198 by the kernel vfs layer before we get here (ie
1199 before read super) so there is no point trying to
1200 parse these options again and set anything and it
1201 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 continue;
1203 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001204 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 } else if (strnicmp(data, "hard", 4) == 0) {
1206 vol->retry = 1;
1207 } else if (strnicmp(data, "soft", 4) == 0) {
1208 vol->retry = 0;
1209 } else if (strnicmp(data, "perm", 4) == 0) {
1210 vol->noperm = 0;
1211 } else if (strnicmp(data, "noperm", 6) == 0) {
1212 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001213 } else if (strnicmp(data, "mapchars", 8) == 0) {
1214 vol->remap = 1;
1215 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1216 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001217 } else if (strnicmp(data, "sfu", 3) == 0) {
1218 vol->sfu_emul = 1;
1219 } else if (strnicmp(data, "nosfu", 5) == 0) {
1220 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001221 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1222 vol->posix_paths = 1;
1223 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1224 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001225 } else if (strnicmp(data, "nounix", 6) == 0) {
1226 vol->no_linux_ext = 1;
1227 } else if (strnicmp(data, "nolinux", 7) == 0) {
1228 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001229 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001230 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001231 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001232 } else if (strnicmp(data, "brl", 3) == 0) {
1233 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001234 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001235 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001236 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001237 /* turn off mandatory locking in mode
1238 if remote locking is turned off since the
1239 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001240 if (vol->file_mode ==
1241 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001242 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 } else if (strnicmp(data, "setuids", 7) == 0) {
1244 vol->setuids = 1;
1245 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1246 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001247 } else if (strnicmp(data, "dynperm", 7) == 0) {
1248 vol->dynperm = true;
1249 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1250 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 } else if (strnicmp(data, "nohard", 6) == 0) {
1252 vol->retry = 0;
1253 } else if (strnicmp(data, "nosoft", 6) == 0) {
1254 vol->retry = 1;
1255 } else if (strnicmp(data, "nointr", 6) == 0) {
1256 vol->intr = 0;
1257 } else if (strnicmp(data, "intr", 4) == 0) {
1258 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001259 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001261 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001263 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001264 vol->cifs_acl = 1;
1265 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1266 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001267 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001269 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001271 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001272 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001273 } else if (strnicmp(data, "seal", 4) == 0) {
1274 /* we do not do the following in secFlags because seal
1275 is a per tree connection (mount) not a per socket
1276 or per-smb connection option in the protocol */
1277 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1278 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001279 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001281 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001283 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 if (!value || !*value) {
1285 vol->in6_addr = NULL;
1286 } else if (strnlen(value, 49) == 48) {
1287 vol->in6_addr = value;
1288 } else {
Steve French50c2f752007-07-13 00:33:32 +00001289 printk(KERN_WARNING "CIFS: ip v6 address not "
1290 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 return 1;
1292 }
1293 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001294 printk(KERN_WARNING "CIFS: Mount option noac not "
1295 "supported. Instead set "
1296 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 } else
Steve French50c2f752007-07-13 00:33:32 +00001298 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1299 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 }
1301 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001302 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001303 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1304 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 return 1;
1306 }
1307 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001308 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001309 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001311 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 if (strncmp(vol->UNC, "//", 2) == 0) {
1313 vol->UNC[0] = '\\';
1314 vol->UNC[1] = '\\';
1315 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001316 printk(KERN_WARNING "CIFS: UNC Path does not "
1317 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 return 1;
1319 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001320 value = strpbrk(vol->UNC+2, "/\\");
1321 if (value)
1322 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 } else {
1324 printk(KERN_WARNING "CIFS: UNC name too long\n");
1325 return 1;
1326 }
1327 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001328 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 vol->UNCip = &vol->UNC[2];
1330
1331 return 0;
1332}
1333
1334static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001335cifs_find_tcp_session(struct in_addr *target_ip_addr,
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001336 struct in6_addr *target_ip6_addr,
1337 char *userName, struct TCP_Server_Info **psrvTcp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338{
1339 struct list_head *tmp;
1340 struct cifsSesInfo *ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001342 *psrvTcp = NULL;
1343
1344 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 list_for_each(tmp, &GlobalSMBSessionList) {
1346 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001347 if (!ses->server)
1348 continue;
Steve French50c2f752007-07-13 00:33:32 +00001349
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001350 if (target_ip_addr &&
1351 ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
1352 continue;
1353 else if (target_ip6_addr &&
1354 memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1355 target_ip6_addr, sizeof(*target_ip6_addr)))
1356 continue;
Jeff Layton02eadef2008-05-09 21:26:11 +00001357 /* BB lock server and tcp session; increment use count here?? */
Steve French50c2f752007-07-13 00:33:32 +00001358
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001359 /* found a match on the TCP session */
1360 *psrvTcp = ses->server;
1361
1362 /* BB check if reconnection needed */
1363 if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
1364 read_unlock(&GlobalSMBSeslock);
1365 /* Found exact match on both TCP and
1366 SMB sessions */
1367 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 }
1369 /* else tcp and smb sessions need reconnection */
1370 }
1371 read_unlock(&GlobalSMBSeslock);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 return NULL;
1374}
1375
1376static struct cifsTconInfo *
1377find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1378{
1379 struct list_head *tmp;
1380 struct cifsTconInfo *tcon;
Steve Frenchdea570e02008-05-06 22:05:51 +00001381 __be32 old_ip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 read_lock(&GlobalSMBSeslock);
Steve Frenchdea570e02008-05-06 22:05:51 +00001384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001386 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchdea570e02008-05-06 22:05:51 +00001388 if (!tcon->ses || !tcon->ses->server)
1389 continue;
1390
1391 old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
1392 cFYI(1, ("old ip addr: %x == new ip %x ?",
1393 old_ip, new_target_ip_addr));
1394
1395 if (old_ip != new_target_ip_addr)
1396 continue;
1397
1398 /* BB lock tcon, server, tcp session and increment use count? */
1399 /* found a match on the TCP session */
1400 /* BB check if reconnection needed */
1401 cFYI(1, ("IP match, old UNC: %s new: %s",
1402 tcon->treeName, uncName));
1403
1404 if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
1405 continue;
1406
1407 cFYI(1, ("and old usr: %s new: %s",
1408 tcon->treeName, uncName));
1409
1410 if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
1411 continue;
1412
1413 /* matched smb session (user name) */
1414 read_unlock(&GlobalSMBSeslock);
1415 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 read_unlock(&GlobalSMBSeslock);
1419 return NULL;
1420}
1421
1422int
Steve French50c2f752007-07-13 00:33:32 +00001423get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1424 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001425 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426{
1427 char *temp_unc;
1428 int rc = 0;
1429
1430 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001431 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
1433 if (pSesInfo->ipc_tid == 0) {
1434 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001435 strnlen(pSesInfo->serverName,
1436 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 + 1 + 4 /* slash IPC$ */ + 2,
1438 GFP_KERNEL);
1439 if (temp_unc == NULL)
1440 return -ENOMEM;
1441 temp_unc[0] = '\\';
1442 temp_unc[1] = '\\';
1443 strcpy(temp_unc + 2, pSesInfo->serverName);
1444 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1445 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1446 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001447 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 kfree(temp_unc);
1449 }
1450 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001451 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001452 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001453 /* BB map targetUNCs to dfs_info3 structures, here or
1454 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455
1456 return rc;
1457}
1458
Jeff Layton09e50d52008-07-23 10:11:19 -04001459#ifdef CONFIG_DEBUG_LOCK_ALLOC
1460static struct lock_class_key cifs_key[2];
1461static struct lock_class_key cifs_slock_key[2];
1462
1463static inline void
1464cifs_reclassify_socket4(struct socket *sock)
1465{
1466 struct sock *sk = sock->sk;
1467 BUG_ON(sock_owned_by_user(sk));
1468 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1469 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1470}
1471
1472static inline void
1473cifs_reclassify_socket6(struct socket *sock)
1474{
1475 struct sock *sk = sock->sk;
1476 BUG_ON(sock_owned_by_user(sk));
1477 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1478 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1479}
1480#else
1481static inline void
1482cifs_reclassify_socket4(struct socket *sock)
1483{
1484}
1485
1486static inline void
1487cifs_reclassify_socket6(struct socket *sock)
1488{
1489}
1490#endif
1491
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001493static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
Steve French50c2f752007-07-13 00:33:32 +00001495 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
Steve French50c2f752007-07-13 00:33:32 +00001497 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 /* mask a nibble at a time and encode */
1499 target[j] = 'A' + (0x0F & (source[i] >> 4));
1500 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001501 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 }
1503
1504}
1505
1506
1507static int
Steve French50c2f752007-07-13 00:33:32 +00001508ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1509 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510{
1511 int rc = 0;
1512 int connected = 0;
1513 __be16 orig_port = 0;
1514
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001515 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001516 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1517 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001519 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 *csocket = NULL;
1521 return rc;
1522 } else {
1523 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001524 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001525 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001526 cifs_reclassify_socket4(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 }
1528 }
1529
1530 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001531 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 rc = (*csocket)->ops->connect(*csocket,
1533 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001534 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 if (rc >= 0)
1536 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001539 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001540 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 later if fall back ports fail this time */
1542 orig_port = psin_server->sin_port;
1543
1544 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001545 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 psin_server->sin_port = htons(CIFS_PORT);
1547
1548 rc = (*csocket)->ops->connect(*csocket,
1549 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001550 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 if (rc >= 0)
1552 connected = 1;
1553 }
1554 }
1555 if (!connected) {
1556 psin_server->sin_port = htons(RFC1001_PORT);
1557 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001558 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001559 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001560 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 connected = 1;
1562 }
1563
1564 /* give up here - unless we want to retry on different
1565 protocol families some day */
1566 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001567 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001569 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 sock_release(*csocket);
1571 *csocket = NULL;
1572 return rc;
1573 }
Steve French50c2f752007-07-13 00:33:32 +00001574 /* Eventually check for other socket options to change from
1575 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001577 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1578 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001579 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001581 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001582 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001583 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001584 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001585 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001588 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001590 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001592 struct rfc1002_session_packet *ses_init_buf;
1593 struct smb_hdr *smb_buf;
1594 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1595 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001596 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001598 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001599 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1600 target_name, 16);
1601 } else {
1602 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001603 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001604 }
1605
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 ses_init_buf->trailer.session_req.calling_len = 32;
1607 /* calling name ends in null (byte 16) from old smb
1608 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001609 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001611 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 } else {
1613 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001614 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 }
1616 ses_init_buf->trailer.session_req.scope1 = 0;
1617 ses_init_buf->trailer.session_req.scope2 = 0;
1618 smb_buf = (struct smb_hdr *)ses_init_buf;
1619 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1620 smb_buf->smb_buf_length = 0x81000044;
1621 rc = smb_send(*csocket, smb_buf, 0x44,
1622 (struct sockaddr *)psin_server);
1623 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001624 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001625 requires very short break before negprot
1626 presumably because not expecting negprot
1627 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001628 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001629 complicating the code and causes no
1630 significant slowing down on mount
1631 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 }
Steve French50c2f752007-07-13 00:33:32 +00001633 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001635
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 }
Steve French50c2f752007-07-13 00:33:32 +00001637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 return rc;
1639}
1640
1641static int
1642ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1643{
1644 int rc = 0;
1645 int connected = 0;
1646 __be16 orig_port = 0;
1647
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001648 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001649 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1650 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001652 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 *csocket = NULL;
1654 return rc;
1655 } else {
1656 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001657 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001659 cifs_reclassify_socket6(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 }
1661 }
1662
1663 psin_server->sin6_family = AF_INET6;
1664
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001665 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 rc = (*csocket)->ops->connect(*csocket,
1667 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001668 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 if (rc >= 0)
1670 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001671 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001673 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001674 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 later if fall back ports fail this time */
1676
1677 orig_port = psin_server->sin6_port;
1678 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001679 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 psin_server->sin6_port = htons(CIFS_PORT);
1681
1682 rc = (*csocket)->ops->connect(*csocket,
1683 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001684 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 if (rc >= 0)
1686 connected = 1;
1687 }
1688 }
1689 if (!connected) {
1690 psin_server->sin6_port = htons(RFC1001_PORT);
1691 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001692 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001693 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 connected = 1;
1695 }
1696
1697 /* give up here - unless we want to retry on different
1698 protocol families some day */
1699 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001700 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001702 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 sock_release(*csocket);
1704 *csocket = NULL;
1705 return rc;
1706 }
Steve French50c2f752007-07-13 00:33:32 +00001707 /* Eventually check for other socket options to change from
1708 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 user space buffer */
1710 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001711
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 return rc;
1713}
1714
Steve French50c2f752007-07-13 00:33:32 +00001715void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1716 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001717{
1718 /* if we are reconnecting then should we check to see if
1719 * any requested capabilities changed locally e.g. via
1720 * remount but we can not do much about it here
1721 * if they have (even if we could detect it by the following)
1722 * Perhaps we could add a backpointer to array of sb from tcon
1723 * or if we change to make all sb to same share the same
1724 * sb as NFS - then we only have one backpointer to sb.
1725 * What if we wanted to mount the server share twice once with
1726 * and once without posixacls or posix paths? */
1727 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001728
Steve Frenchc18c8422007-07-18 23:21:09 +00001729 if (vol_info && vol_info->no_linux_ext) {
1730 tcon->fsUnixInfo.Capability = 0;
1731 tcon->unix_ext = 0; /* Unix Extensions disabled */
1732 cFYI(1, ("Linux protocol extensions disabled"));
1733 return;
1734 } else if (vol_info)
1735 tcon->unix_ext = 1; /* Unix Extensions supported */
1736
1737 if (tcon->unix_ext == 0) {
1738 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1739 return;
1740 }
Steve French50c2f752007-07-13 00:33:32 +00001741
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001742 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001743 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001744
Steve French8af18972007-02-14 04:42:51 +00001745 /* check for reconnect case in which we do not
1746 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001747 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001748 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001749 originally at mount time */
1750 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1751 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001752 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1753 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1754 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001755 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001756 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1757 cERROR(1, ("possible reconnect error"));
1758 cERROR(1,
1759 ("server disabled POSIX path support"));
1760 }
Steve French8af18972007-02-14 04:42:51 +00001761 }
Steve French50c2f752007-07-13 00:33:32 +00001762
Steve French8af18972007-02-14 04:42:51 +00001763 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001764 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001765 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001766 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001767 cFYI(1, ("negotiated posix acl support"));
1768 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001769 sb->s_flags |= MS_POSIXACL;
1770 }
1771
Steve French75865f8c2007-06-24 18:30:48 +00001772 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001773 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001774 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001775 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001776 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001777 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001778 CIFS_MOUNT_POSIX_PATHS;
1779 }
Steve French50c2f752007-07-13 00:33:32 +00001780
Steve French984acfe2007-04-26 16:42:50 +00001781 /* We might be setting the path sep back to a different
1782 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001783 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001784 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001785 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001786
1787 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1788 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1789 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00001790 cFYI(DBG2,
1791 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001792 }
1793 }
Steve French50c2f752007-07-13 00:33:32 +00001794
1795
1796 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001797#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001798 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001799 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001800 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001801 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001802 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001803 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001804 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001805 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001806 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001807 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001808 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001809 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001810 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001811 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001812#endif /* CIFS_DEBUG2 */
1813 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001814 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001815 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001816 } else
Steve French5a44b312007-09-20 15:16:24 +00001817 cERROR(1, ("Negotiating Unix capabilities "
1818 "with the server failed. Consider "
1819 "mounting with the Unix Extensions\n"
1820 "disabled, if problems are found, "
1821 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001822 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001823
Steve French8af18972007-02-14 04:42:51 +00001824 }
1825 }
1826}
1827
Steve French03a143c2008-02-14 06:38:30 +00001828static void
1829convert_delimiter(char *path, char delim)
1830{
1831 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001832 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00001833
1834 if (path == NULL)
1835 return;
1836
Steve French582d21e2008-05-13 04:54:12 +00001837 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001838 old_delim = '\\';
1839 else
1840 old_delim = '/';
1841
Steve French03a143c2008-02-14 06:38:30 +00001842 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001843 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00001844 path[i] = delim;
1845 }
1846}
1847
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848int
1849cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1850 char *mount_data, const char *devname)
1851{
1852 int rc = 0;
1853 int xid;
1854 int address_type = AF_INET;
1855 struct socket *csocket = NULL;
1856 struct sockaddr_in sin_server;
1857 struct sockaddr_in6 sin_server6;
1858 struct smb_vol volume_info;
1859 struct cifsSesInfo *pSesInfo = NULL;
1860 struct cifsSesInfo *existingCifsSes = NULL;
1861 struct cifsTconInfo *tcon = NULL;
1862 struct TCP_Server_Info *srvTcp = NULL;
1863
1864 xid = GetXid();
1865
1866/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001867
1868 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001870 rc = -EINVAL;
1871 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 }
1873
Jeff Layton8426c392007-05-05 03:27:49 +00001874 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001875 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001876 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001877 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001879 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001881 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001882 /* In userspace mount helper we can get user name from alternate
1883 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001884 rc = -EINVAL;
1885 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 }
1887
1888 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001889 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1890 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001892 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001894 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1895 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001896 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 address_type = AF_INET6;
1898 } else {
1899 address_type = AF_INET;
1900 }
Steve French50c2f752007-07-13 00:33:32 +00001901
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001902 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001904 rc = -EINVAL;
1905 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
1907
1908 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1909 /* success */
1910 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001911 } else if (volume_info.UNCip) {
1912 /* BB using ip addr as server name to connect to the
1913 DFS root below */
1914 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001915 rc = -EINVAL;
1916 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 } else /* which servers DFS root would we conect to */ {
1918 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001919 ("CIFS mount error: No UNC path (e.g. -o "
1920 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001921 rc = -EINVAL;
1922 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 }
1924
1925 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001926 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 cifs_sb->local_nls = load_nls_default();
1928 /* load_nls_default can not return null */
1929 } else {
1930 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001931 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001932 cERROR(1, ("CIFS mount error: iocharset %s not found",
1933 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001934 rc = -ELIBACC;
1935 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
1937 }
1938
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001939 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1941 NULL /* no ipv6 addr */,
1942 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001943 else if (address_type == AF_INET6) {
1944 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1946 &sin_server6.sin6_addr,
1947 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001948 } else {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001949 rc = -EINVAL;
1950 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 }
1952
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001954 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001956 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 sin_server.sin_port = htons(volume_info.port);
1958 else
1959 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001960 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001961 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001962 /* BB should we allow ipv6 on port 139? */
1963 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001964 rc = ipv6_connect(&sin_server6, &csocket);
1965 } else
1966 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001967 volume_info.source_rfc1001_name,
1968 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001970 cERROR(1, ("Error connecting to IPv4 socket. "
1971 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001972 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001974 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 }
1976
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001977 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1978 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 rc = -ENOMEM;
1980 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001981 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 } else {
Steve French50c2f752007-07-13 00:33:32 +00001983 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001984 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00001985 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 /* BB Add code for ipv6 case too */
1987 srvTcp->ssocket = csocket;
1988 srvTcp->protocolType = IPV4;
Jeff Laytonc359cf32007-11-16 22:22:06 +00001989 srvTcp->hostname = extract_hostname(volume_info.UNC);
1990 if (IS_ERR(srvTcp->hostname)) {
1991 rc = PTR_ERR(srvTcp->hostname);
1992 sock_release(csocket);
1993 goto out;
1994 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 init_waitqueue_head(&srvTcp->response_q);
1996 init_waitqueue_head(&srvTcp->request_q);
1997 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1998 /* at this point we are the only ones with the pointer
1999 to the struct since the kernel thread not created yet
2000 so no need to spinlock this init of tcpStatus */
2001 srvTcp->tcpStatus = CifsNew;
2002 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002003 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00002004 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002005 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00002006 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002007 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00002009 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002010 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07002011 }
Steve Frenchf1914012005-08-18 09:37:34 -07002012 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002013 memcpy(srvTcp->workstation_RFC1001_name,
2014 volume_info.source_rfc1001_name, 16);
2015 memcpy(srvTcp->server_RFC1001_name,
2016 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07002017 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 }
2019 }
2020
2021 if (existingCifsSes) {
2022 pSesInfo = existingCifsSes;
Jeff Layton1d9a8852007-12-31 01:37:11 +00002023 cFYI(1, ("Existing smb sess found (status=%d)",
2024 pSesInfo->status));
Steve French88e7d702008-01-03 17:37:09 +00002025 down(&pSesInfo->sesSem);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002026 if (pSesInfo->status == CifsNeedReconnect) {
2027 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002028 rc = cifs_setup_session(xid, pSesInfo,
2029 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002030 }
Steve French88e7d702008-01-03 17:37:09 +00002031 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002033 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 pSesInfo = sesInfoAlloc();
2035 if (pSesInfo == NULL)
2036 rc = -ENOMEM;
2037 else {
2038 pSesInfo->server = srvTcp;
2039 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2040 NIPQUAD(sin_server.sin_addr.s_addr));
2041 }
2042
Steve French50c2f752007-07-13 00:33:32 +00002043 if (!rc) {
2044 /* volume_info.password freed at unmount */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002045 if (volume_info.password) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 pSesInfo->password = volume_info.password;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002047 /* set to NULL to prevent freeing on exit */
2048 volume_info.password = NULL;
2049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 if (volume_info.username)
2051 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00002052 volume_info.username,
2053 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00002054 if (volume_info.domainname) {
2055 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00002056 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00002057 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00002058 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00002059 strcpy(pSesInfo->domainName,
2060 volume_info.domainname);
2061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00002063 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00002065 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00002066 rc = cifs_setup_session(xid, pSesInfo,
2067 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00002069 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 atomic_inc(&srvTcp->socketUseCount);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 }
Steve French50c2f752007-07-13 00:33:32 +00002073
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 /* search for existing tcon to this server share */
2075 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002076 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002077 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002078 volume_info.rsize));
2079 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002080 } else if ((volume_info.rsize) &&
2081 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002083 else /* default */
2084 cifs_sb->rsize = CIFSMaxBufSize;
2085
Steve French4523cc32007-04-30 20:13:06 +00002086 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002087 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002088 volume_info.wsize));
2089 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002090 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 cifs_sb->wsize = volume_info.wsize;
2092 else
Steve French50c2f752007-07-13 00:33:32 +00002093 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002094 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2095 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002096 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002097 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002098 RFC1001 does not describe what happens when frame
2099 bigger than 128K is sent so use that as max in
2100 conjunction with 52K kvec constraint on arch with 4K
2101 page size */
2102
Steve French4523cc32007-04-30 20:13:06 +00002103 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002104 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002105 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002106 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 }
Steve French2fe87f02006-09-21 07:02:52 +00002108 /* calculate prepath */
2109 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002110 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002111 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
Steve French03a143c2008-02-14 06:38:30 +00002112 /* we can not convert the / to \ in the path
2113 separators in the prefixpath yet because we do not
2114 know (until reset_cifs_unix_caps is called later)
2115 whether POSIX PATH CAP is available. We normalize
2116 the / to \ after reset_cifs_unix_caps is called */
Steve French2fe87f02006-09-21 07:02:52 +00002117 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002118 } else
Steve French2fe87f02006-09-21 07:02:52 +00002119 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 cifs_sb->mnt_uid = volume_info.linux_uid;
2121 cifs_sb->mnt_gid = volume_info.linux_gid;
2122 cifs_sb->mnt_file_mode = volume_info.file_mode;
2123 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002124 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2125 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
Steve French4523cc32007-04-30 20:13:06 +00002127 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002129 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002131 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002133 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002134 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002135 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002137 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002138 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002139 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002140 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002141 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002142 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002143 if (volume_info.override_uid)
2144 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2145 if (volume_info.override_gid)
2146 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
Jeff Laytond0a9c072008-05-12 22:23:49 +00002147 if (volume_info.dynperm)
2148 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Steve French4523cc32007-04-30 20:13:06 +00002149 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002150 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2152 }
2153
Steve French27adb442008-05-23 19:43:29 +00002154 if ((volume_info.cifs_acl) && (volume_info.dynperm))
2155 cERROR(1, ("mount option dynperm ignored if cifsacl "
2156 "mount option supported"));
2157
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 tcon =
2159 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2160 volume_info.username);
2161 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002162 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 /* we can have only one retry value for a connection
2164 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002165 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 for the retry flag is used */
2167 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002168 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002169 if (tcon->seal != volume_info.seal)
2170 cERROR(1, ("transport encryption setting "
2171 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 } else {
2173 tcon = tconInfoAlloc();
2174 if (tcon == NULL)
2175 rc = -ENOMEM;
2176 else {
Steve French50c2f752007-07-13 00:33:32 +00002177 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002178 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
Steve French50c2f752007-07-13 00:33:32 +00002180 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002181 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2183 && (strchr(volume_info.UNC + 3, '/') ==
2184 NULL)) {
Steve French646dd532008-05-15 01:50:56 +00002185/* rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002186 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002187 cifs_sb->mnt_cifs_flags &
Steve French646dd532008-05-15 01:50:56 +00002188 CIFS_MOUNT_MAP_SPECIAL_CHR);*/
2189 cFYI(1, ("DFS root not supported"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002190 rc = -ENODEV;
2191 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 } else {
Steve French8af18972007-02-14 04:42:51 +00002193 /* BB Do we need to wrap sesSem around
2194 * this TCon call and Unix SetFS as
2195 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002196 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 volume_info.UNC,
2198 tcon, cifs_sb->local_nls);
2199 cFYI(1, ("CIFS Tcon rc = %d", rc));
2200 }
2201 if (!rc) {
2202 atomic_inc(&pSesInfo->inUse);
2203 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002204 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002205 tcon->seal = volume_info.seal;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 }
2207 }
2208 }
2209 }
Steve French4523cc32007-04-30 20:13:06 +00002210 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2212 sb->s_maxbytes = (u64) 1 << 63;
2213 } else
2214 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2215 }
2216
Steve French8af18972007-02-14 04:42:51 +00002217 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 sb->s_time_gran = 100;
2219
2220/* on error free sesinfo and tcon struct if needed */
2221 if (rc) {
2222 /* if session setup failed, use count is zero but
2223 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002224 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 spin_lock(&GlobalMid_Lock);
2226 srvTcp->tcpStatus = CifsExiting;
2227 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002228 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002229 /* If we could verify that kthread_stop would
2230 always wake up processes blocked in
2231 tcp in recv_mesg then we could remove the
2232 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002233 force_sig(SIGKILL, srvTcp->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002234 kthread_stop(srvTcp->tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 }
2237 /* If find_unc succeeded then rc == 0 so we can not end */
2238 if (tcon) /* up accidently freeing someone elses tcon struct */
2239 tconInfoFree(tcon);
2240 if (existingCifsSes == NULL) {
2241 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002242 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 (pSesInfo->status == CifsGood)) {
2244 int temp_rc;
2245 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2246 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002247 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002248 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002249 (pSesInfo->server->tsk)) {
Jeff5d9c7202007-06-25 22:16:35 +00002250 force_sig(SIGKILL,
2251 pSesInfo->server->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002252 kthread_stop(pSesInfo->server->tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002253 }
Steve Frencha0136892007-10-04 20:05:09 +00002254 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 cFYI(1, ("No session or bad tcon"));
Steve Frencha0136892007-10-04 20:05:09 +00002256 if ((pSesInfo->server) &&
2257 (pSesInfo->server->tsk)) {
Steve Frencha0136892007-10-04 20:05:09 +00002258 force_sig(SIGKILL,
2259 pSesInfo->server->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002260 kthread_stop(pSesInfo->server->tsk);
Steve Frencha0136892007-10-04 20:05:09 +00002261 }
2262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 sesInfoFree(pSesInfo);
2264 /* pSesInfo = NULL; */
2265 }
2266 }
2267 } else {
2268 atomic_inc(&tcon->useCount);
2269 cifs_sb->tcon = tcon;
2270 tcon->ses = pSesInfo;
2271
Steve French82940a42006-03-02 03:24:57 +00002272 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002273 if (!tcon->ipc) {
2274 CIFSSMBQFSDeviceInfo(xid, tcon);
2275 CIFSSMBQFSAttributeInfo(xid, tcon);
2276 }
Steve French50c2f752007-07-13 00:33:32 +00002277
Steve French8af18972007-02-14 04:42:51 +00002278 /* tell server which Unix caps we support */
2279 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002280 /* reset of caps checks mount to see if unix extensions
2281 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002282 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002283 else
2284 tcon->unix_ext = 0; /* server does not support them */
2285
Steve French03a143c2008-02-14 06:38:30 +00002286 /* convert forward to back slashes in prepath here if needed */
Igor Mammedov11b6d642008-02-15 19:06:04 +00002287 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2288 convert_delimiter(cifs_sb->prepath,
2289 CIFS_DIR_SEP(cifs_sb));
Steve French03a143c2008-02-14 06:38:30 +00002290
Steve Frenchc18c8422007-07-18 23:21:09 +00002291 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002292 cifs_sb->rsize = 1024 * 127;
Steve French90c81e02008-02-12 20:32:36 +00002293 cFYI(DBG2,
2294 ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002295 }
Steve French3e844692005-10-03 13:37:24 -07002296 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2297 cifs_sb->wsize = min(cifs_sb->wsize,
2298 (tcon->ses->server->maxBuf -
2299 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002300 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002301 cifs_sb->rsize = min(cifs_sb->rsize,
2302 (tcon->ses->server->maxBuf -
2303 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 }
2305
2306 /* volume_info.password is freed above when existing session found
2307 (in which case it is not needed anymore) but when new sesion is created
2308 the password ptr is put in the new session structure (in which case the
2309 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002310out:
2311 /* zero out password before freeing */
2312 if (volume_info.password != NULL) {
2313 memset(volume_info.password, 0, strlen(volume_info.password));
2314 kfree(volume_info.password);
2315 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002316 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002317 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 FreeXid(xid);
2319 return rc;
2320}
2321
2322static int
2323CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002324 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 const struct nls_table *nls_codepage)
2326{
2327 struct smb_hdr *smb_buffer;
2328 struct smb_hdr *smb_buffer_response;
2329 SESSION_SETUP_ANDX *pSMB;
2330 SESSION_SETUP_ANDX *pSMBr;
2331 char *bcc_ptr;
2332 char *user;
2333 char *domain;
2334 int rc = 0;
2335 int remaining_words = 0;
2336 int bytes_returned = 0;
2337 int len;
2338 __u32 capabilities;
2339 __u16 count;
2340
Steve Frencheeac8042006-01-13 21:34:58 -08002341 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002342 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 return -EINVAL;
2344 user = ses->userName;
2345 domain = ses->domainName;
2346 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002347
2348 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002350
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 smb_buffer_response = smb_buffer;
2352 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2353
2354 /* send SMBsessionSetup here */
2355 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2356 NULL /* no tCon exists yet */ , 13 /* wct */ );
2357
Steve French1982c342005-08-17 12:38:22 -07002358 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 pSMB->req_no_secext.AndXCommand = 0xFF;
2360 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2361 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2362
Steve French50c2f752007-07-13 00:33:32 +00002363 if (ses->server->secMode &
2364 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2366
2367 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2368 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2369 if (ses->capabilities & CAP_UNICODE) {
2370 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2371 capabilities |= CAP_UNICODE;
2372 }
2373 if (ses->capabilities & CAP_STATUS32) {
2374 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2375 capabilities |= CAP_STATUS32;
2376 }
2377 if (ses->capabilities & CAP_DFS) {
2378 smb_buffer->Flags2 |= SMBFLG2_DFS;
2379 capabilities |= CAP_DFS;
2380 }
2381 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2382
Steve French50c2f752007-07-13 00:33:32 +00002383 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002384 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
2386 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002387 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002389 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2390 bcc_ptr += CIFS_SESS_KEY_SIZE;
2391 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2392 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393
2394 if (ses->capabilities & CAP_UNICODE) {
2395 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2396 *bcc_ptr = 0;
2397 bcc_ptr++;
2398 }
Steve French4523cc32007-04-30 20:13:06 +00002399 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002400 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002401 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002403 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 nls_codepage);
2405 /* convert number of 16 bit words to bytes */
2406 bcc_ptr += 2 * bytes_returned;
2407 bcc_ptr += 2; /* trailing null */
2408 if (domain == NULL)
2409 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002410 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 "CIFS_LINUX_DOM", 32, nls_codepage);
2412 else
2413 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002414 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 nls_codepage);
2416 bcc_ptr += 2 * bytes_returned;
2417 bcc_ptr += 2;
2418 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002419 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 32, nls_codepage);
2421 bcc_ptr += 2 * bytes_returned;
2422 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002423 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 32, nls_codepage);
2425 bcc_ptr += 2 * bytes_returned;
2426 bcc_ptr += 2;
2427 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002428 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 64, nls_codepage);
2430 bcc_ptr += 2 * bytes_returned;
2431 bcc_ptr += 2;
2432 } else {
Steve French50c2f752007-07-13 00:33:32 +00002433 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 strncpy(bcc_ptr, user, 200);
2435 bcc_ptr += strnlen(user, 200);
2436 }
2437 *bcc_ptr = 0;
2438 bcc_ptr++;
2439 if (domain == NULL) {
2440 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2441 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2442 } else {
2443 strncpy(bcc_ptr, domain, 64);
2444 bcc_ptr += strnlen(domain, 64);
2445 *bcc_ptr = 0;
2446 bcc_ptr++;
2447 }
2448 strcpy(bcc_ptr, "Linux version ");
2449 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002450 strcpy(bcc_ptr, utsname()->release);
2451 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2453 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2454 }
2455 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2456 smb_buffer->smb_buf_length += count;
2457 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2458
2459 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002460 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 if (rc) {
2462/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2463 } else if ((smb_buffer_response->WordCount == 3)
2464 || (smb_buffer_response->WordCount == 4)) {
2465 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2466 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2467 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002468 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2469 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2470 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002472 /* response can have either 3 or 4 word count - Samba sends 3 */
2473 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 if ((pSMBr->resp.hdr.WordCount == 3)
2475 || ((pSMBr->resp.hdr.WordCount == 4)
2476 && (blob_len < pSMBr->resp.ByteCount))) {
2477 if (pSMBr->resp.hdr.WordCount == 4)
2478 bcc_ptr += blob_len;
2479
2480 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2481 if ((long) (bcc_ptr) % 2) {
2482 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002483 (BCC(smb_buffer_response) - 1) / 2;
2484 /* Unicode strings must be word
2485 aligned */
2486 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 } else {
2488 remaining_words =
2489 BCC(smb_buffer_response) / 2;
2490 }
2491 len =
2492 UniStrnlen((wchar_t *) bcc_ptr,
2493 remaining_words - 1);
2494/* We look for obvious messed up bcc or strings in response so we do not go off
2495 the end since (at least) WIN2K and Windows XP have a major bug in not null
2496 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002497 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002498 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002499 ses->serverOS = kzalloc(2 * (len + 1),
2500 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002501 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002502 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002504 (__le16 *)bcc_ptr,
2505 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 bcc_ptr += 2 * (len + 1);
2507 remaining_words -= len + 1;
2508 ses->serverOS[2 * len] = 0;
2509 ses->serverOS[1 + (2 * len)] = 0;
2510 if (remaining_words > 0) {
2511 len = UniStrnlen((wchar_t *)bcc_ptr,
2512 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002513 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002514 ses->serverNOS = kzalloc(2 * (len + 1),
2515 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002516 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002517 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002519 (__le16 *)bcc_ptr,
2520 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 bcc_ptr += 2 * (len + 1);
2522 ses->serverNOS[2 * len] = 0;
2523 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002524 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002525 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002526 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 ses->flags |= CIFS_SES_NT4;
2528 }
2529 remaining_words -= len + 1;
2530 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002531 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002532 /* last string is not always null terminated
2533 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002534 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002535 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002537 kzalloc(2*(len+1),
2538 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002539 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002540 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002542 (__le16 *)bcc_ptr,
2543 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 bcc_ptr += 2 * (len + 1);
2545 ses->serverDomain[2*len] = 0;
2546 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002547 } else { /* else no more room so create
2548 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002549 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002550 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002551 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002552 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002553 }
Steve French50c2f752007-07-13 00:33:32 +00002554 } else { /* no room so create dummy domain
2555 and NOS string */
2556
Steve French433dc242005-04-28 22:41:08 -07002557 /* if these kcallocs fail not much we
2558 can do, but better to not fail the
2559 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002560 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002562 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002563 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002565 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 }
2567 } else { /* ASCII */
2568 len = strnlen(bcc_ptr, 1024);
2569 if (((long) bcc_ptr + len) - (long)
2570 pByteArea(smb_buffer_response)
2571 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002572 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002573 ses->serverOS = kzalloc(len + 1,
2574 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002575 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002576 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002577 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
2579 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002580 /* null terminate the string */
2581 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 bcc_ptr++;
2583
2584 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002585 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002586 ses->serverNOS = kzalloc(len + 1,
2587 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002588 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002589 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 strncpy(ses->serverNOS, bcc_ptr, len);
2591 bcc_ptr += len;
2592 bcc_ptr[0] = 0;
2593 bcc_ptr++;
2594
2595 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002596 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002597 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002598 ses->serverDomain = kzalloc(len + 1,
2599 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002600 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002601 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002602 strncpy(ses->serverDomain, bcc_ptr,
2603 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 bcc_ptr += len;
2605 bcc_ptr[0] = 0;
2606 bcc_ptr++;
2607 } else
2608 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002609 ("Variable field of length %d "
2610 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 len));
2612 }
2613 } else {
2614 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002615 (" Security Blob Length extends beyond "
2616 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 }
2618 } else {
2619 cERROR(1,
2620 (" Invalid Word count %d: ",
2621 smb_buffer_response->WordCount));
2622 rc = -EIO;
2623 }
Steve French433dc242005-04-28 22:41:08 -07002624sesssetup_nomem: /* do not return an error on nomem for the info strings,
2625 since that could make reconnection harder, and
2626 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002627 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629 return rc;
2630}
2631
2632static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002634 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 const struct nls_table *nls_codepage)
2636{
2637 struct smb_hdr *smb_buffer;
2638 struct smb_hdr *smb_buffer_response;
2639 SESSION_SETUP_ANDX *pSMB;
2640 SESSION_SETUP_ANDX *pSMBr;
2641 char *bcc_ptr;
2642 char *domain;
2643 int rc = 0;
2644 int remaining_words = 0;
2645 int bytes_returned = 0;
2646 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002647 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 PNEGOTIATE_MESSAGE SecurityBlob;
2649 PCHALLENGE_MESSAGE SecurityBlob2;
2650 __u32 negotiate_flags, capabilities;
2651 __u16 count;
2652
Steve French12b3b8f2006-02-09 21:12:47 +00002653 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002654 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return -EINVAL;
2656 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002657 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 smb_buffer = cifs_buf_get();
2659 if (smb_buffer == NULL) {
2660 return -ENOMEM;
2661 }
2662 smb_buffer_response = smb_buffer;
2663 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2664 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2665
2666 /* send SMBsessionSetup here */
2667 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2668 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002669
2670 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2672 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2673
2674 pSMB->req.AndXCommand = 0xFF;
2675 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2676 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2677
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002678 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2680
2681 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2682 CAP_EXTENDED_SECURITY;
2683 if (ses->capabilities & CAP_UNICODE) {
2684 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2685 capabilities |= CAP_UNICODE;
2686 }
2687 if (ses->capabilities & CAP_STATUS32) {
2688 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2689 capabilities |= CAP_STATUS32;
2690 }
2691 if (ses->capabilities & CAP_DFS) {
2692 smb_buffer->Flags2 |= SMBFLG2_DFS;
2693 capabilities |= CAP_DFS;
2694 }
2695 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2696
2697 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2698 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2699 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2700 SecurityBlob->MessageType = NtLmNegotiate;
2701 negotiate_flags =
2702 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002703 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2704 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002706 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002708/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002709 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 /* setup pointers to domain name and workstation name */
2711 bcc_ptr += SecurityBlobLength;
2712
2713 SecurityBlob->WorkstationName.Buffer = 0;
2714 SecurityBlob->WorkstationName.Length = 0;
2715 SecurityBlob->WorkstationName.MaximumLength = 0;
2716
Steve French12b3b8f2006-02-09 21:12:47 +00002717 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2718 along with username on auth request (ie the response to challenge) */
2719 SecurityBlob->DomainName.Buffer = 0;
2720 SecurityBlob->DomainName.Length = 0;
2721 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 if (ses->capabilities & CAP_UNICODE) {
2723 if ((long) bcc_ptr % 2) {
2724 *bcc_ptr = 0;
2725 bcc_ptr++;
2726 }
2727
2728 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002729 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 32, nls_codepage);
2731 bcc_ptr += 2 * bytes_returned;
2732 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002733 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 nls_codepage);
2735 bcc_ptr += 2 * bytes_returned;
2736 bcc_ptr += 2; /* null terminate Linux version */
2737 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002738 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 64, nls_codepage);
2740 bcc_ptr += 2 * bytes_returned;
2741 *(bcc_ptr + 1) = 0;
2742 *(bcc_ptr + 2) = 0;
2743 bcc_ptr += 2; /* null terminate network opsys string */
2744 *(bcc_ptr + 1) = 0;
2745 *(bcc_ptr + 2) = 0;
2746 bcc_ptr += 2; /* null domain */
2747 } else { /* ASCII */
2748 strcpy(bcc_ptr, "Linux version ");
2749 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002750 strcpy(bcc_ptr, utsname()->release);
2751 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2753 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2754 bcc_ptr++; /* empty domain field */
2755 *bcc_ptr = 0;
2756 }
2757 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2758 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2759 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2760 smb_buffer->smb_buf_length += count;
2761 pSMB->req.ByteCount = cpu_to_le16(count);
2762
2763 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002764 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765
2766 if (smb_buffer_response->Status.CifsError ==
2767 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2768 rc = 0;
2769
2770 if (rc) {
2771/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2772 } else if ((smb_buffer_response->WordCount == 3)
2773 || (smb_buffer_response->WordCount == 4)) {
2774 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2775 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2776
2777 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002778 cFYI(1, (" Guest login"));
2779 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
Steve French50c2f752007-07-13 00:33:32 +00002781 bcc_ptr = pByteArea(smb_buffer_response);
2782 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2785 if (SecurityBlob2->MessageType != NtLmChallenge) {
2786 cFYI(1,
2787 ("Unexpected NTLMSSP message type received %d",
2788 SecurityBlob2->MessageType));
2789 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002790 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002791 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 if ((pSMBr->resp.hdr.WordCount == 3)
2793 || ((pSMBr->resp.hdr.WordCount == 4)
2794 && (blob_len <
2795 pSMBr->resp.ByteCount))) {
2796
2797 if (pSMBr->resp.hdr.WordCount == 4) {
2798 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002799 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 blob_len));
2801 }
2802
Steve French12b3b8f2006-02-09 21:12:47 +00002803 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
2805 memcpy(ses->server->cryptKey,
2806 SecurityBlob2->Challenge,
2807 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002808 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002809 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002810 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811
Steve French50c2f752007-07-13 00:33:32 +00002812 if ((SecurityBlob2->NegotiateFlags &
2813 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002815 ses->server->secMode |=
2816 SECMODE_SIGN_REQUIRED;
2817 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002819 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 SECMODE_SIGN_ENABLED;
2821
2822 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2823 if ((long) (bcc_ptr) % 2) {
2824 remaining_words =
2825 (BCC(smb_buffer_response)
2826 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002827 /* Must word align unicode strings */
2828 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 } else {
2830 remaining_words =
2831 BCC
2832 (smb_buffer_response) / 2;
2833 }
2834 len =
2835 UniStrnlen((wchar_t *) bcc_ptr,
2836 remaining_words - 1);
2837/* We look for obvious messed up bcc or strings in response so we do not go off
2838 the end since (at least) WIN2K and Windows XP have a major bug in not null
2839 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002840 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002841 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002843 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002845 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 bcc_ptr, len,
2847 nls_codepage);
2848 bcc_ptr += 2 * (len + 1);
2849 remaining_words -= len + 1;
2850 ses->serverOS[2 * len] = 0;
2851 ses->serverOS[1 + (2 * len)] = 0;
2852 if (remaining_words > 0) {
2853 len = UniStrnlen((wchar_t *)
2854 bcc_ptr,
2855 remaining_words
2856 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002857 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002859 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 GFP_KERNEL);
2861 cifs_strfromUCS_le(ses->
2862 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002863 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 bcc_ptr,
2865 len,
2866 nls_codepage);
2867 bcc_ptr += 2 * (len + 1);
2868 ses->serverNOS[2 * len] = 0;
2869 ses->serverNOS[1 +
2870 (2 * len)] = 0;
2871 remaining_words -= len + 1;
2872 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002873 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2874 /* last string not always null terminated
2875 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002876 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002878 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 (len +
2880 1),
2881 GFP_KERNEL);
2882 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002883 (ses->serverDomain,
2884 (__le16 *)bcc_ptr,
2885 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 bcc_ptr +=
2887 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002888 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002890 ses->serverDomain
2891 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 = 0;
2893 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002894 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002895 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002897 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002901 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002903 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002904 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002906 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 }
2908 } else { /* ASCII */
2909 len = strnlen(bcc_ptr, 1024);
2910 if (((long) bcc_ptr + len) - (long)
2911 pByteArea(smb_buffer_response)
2912 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002913 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002914 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002916 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 GFP_KERNEL);
2918 strncpy(ses->serverOS,
2919 bcc_ptr, len);
2920
2921 bcc_ptr += len;
2922 bcc_ptr[0] = 0; /* null terminate string */
2923 bcc_ptr++;
2924
2925 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002926 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002928 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 GFP_KERNEL);
2930 strncpy(ses->serverNOS, bcc_ptr, len);
2931 bcc_ptr += len;
2932 bcc_ptr[0] = 0;
2933 bcc_ptr++;
2934
2935 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002936 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002938 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002940 strncpy(ses->serverDomain,
2941 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 bcc_ptr += len;
2943 bcc_ptr[0] = 0;
2944 bcc_ptr++;
2945 } else
2946 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002947 ("field of length %d "
2948 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 len));
2950 }
2951 } else {
Steve French50c2f752007-07-13 00:33:32 +00002952 cERROR(1, ("Security Blob Length extends beyond"
2953 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 }
2955 } else {
2956 cERROR(1, ("No session structure passed in."));
2957 }
2958 } else {
2959 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002960 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 smb_buffer_response->WordCount));
2962 rc = -EIO;
2963 }
2964
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002965 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
2967 return rc;
2968}
2969static int
2970CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002971 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002972 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973{
2974 struct smb_hdr *smb_buffer;
2975 struct smb_hdr *smb_buffer_response;
2976 SESSION_SETUP_ANDX *pSMB;
2977 SESSION_SETUP_ANDX *pSMBr;
2978 char *bcc_ptr;
2979 char *user;
2980 char *domain;
2981 int rc = 0;
2982 int remaining_words = 0;
2983 int bytes_returned = 0;
2984 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002985 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 PAUTHENTICATE_MESSAGE SecurityBlob;
2987 __u32 negotiate_flags, capabilities;
2988 __u16 count;
2989
2990 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002991 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 return -EINVAL;
2993 user = ses->userName;
2994 domain = ses->domainName;
2995 smb_buffer = cifs_buf_get();
2996 if (smb_buffer == NULL) {
2997 return -ENOMEM;
2998 }
2999 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003000 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3001 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
3003 /* send SMBsessionSetup here */
3004 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3005 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003006
3007 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3009 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3010 pSMB->req.AndXCommand = 0xFF;
3011 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3012 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3013
3014 pSMB->req.hdr.Uid = ses->Suid;
3015
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003016 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3018
3019 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003020 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 if (ses->capabilities & CAP_UNICODE) {
3022 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3023 capabilities |= CAP_UNICODE;
3024 }
3025 if (ses->capabilities & CAP_STATUS32) {
3026 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3027 capabilities |= CAP_STATUS32;
3028 }
3029 if (ses->capabilities & CAP_DFS) {
3030 smb_buffer->Flags2 |= SMBFLG2_DFS;
3031 capabilities |= CAP_DFS;
3032 }
3033 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3034
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003035 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3036 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3038 SecurityBlob->MessageType = NtLmAuthenticate;
3039 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003040 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3041 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3042 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003043 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003045 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3047
3048/* setup pointers to domain name and workstation name */
3049
3050 SecurityBlob->WorkstationName.Buffer = 0;
3051 SecurityBlob->WorkstationName.Length = 0;
3052 SecurityBlob->WorkstationName.MaximumLength = 0;
3053 SecurityBlob->SessionKey.Length = 0;
3054 SecurityBlob->SessionKey.MaximumLength = 0;
3055 SecurityBlob->SessionKey.Buffer = 0;
3056
3057 SecurityBlob->LmChallengeResponse.Length = 0;
3058 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3059 SecurityBlob->LmChallengeResponse.Buffer = 0;
3060
3061 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003062 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003064 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3065 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 SecurityBlob->NtChallengeResponse.Buffer =
3067 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003068 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3069 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070
3071 if (ses->capabilities & CAP_UNICODE) {
3072 if (domain == NULL) {
3073 SecurityBlob->DomainName.Buffer = 0;
3074 SecurityBlob->DomainName.Length = 0;
3075 SecurityBlob->DomainName.MaximumLength = 0;
3076 } else {
Steve French77159b42007-08-31 01:10:17 +00003077 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003079 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003081 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 SecurityBlob->DomainName.Buffer =
3083 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003084 bcc_ptr += ln;
3085 SecurityBlobLength += ln;
3086 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 }
3088 if (user == NULL) {
3089 SecurityBlob->UserName.Buffer = 0;
3090 SecurityBlob->UserName.Length = 0;
3091 SecurityBlob->UserName.MaximumLength = 0;
3092 } else {
Steve French77159b42007-08-31 01:10:17 +00003093 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003095 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003097 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 SecurityBlob->UserName.Buffer =
3099 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003100 bcc_ptr += ln;
3101 SecurityBlobLength += ln;
3102 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 }
3104
Steve French63135e02007-07-17 17:34:02 +00003105 /* SecurityBlob->WorkstationName.Length =
3106 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003108 SecurityBlob->WorkstationName.MaximumLength =
3109 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3110 SecurityBlob->WorkstationName.Buffer =
3111 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 bcc_ptr += SecurityBlob->WorkstationName.Length;
3113 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003114 SecurityBlob->WorkstationName.Length =
3115 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116
3117 if ((long) bcc_ptr % 2) {
3118 *bcc_ptr = 0;
3119 bcc_ptr++;
3120 }
3121 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003122 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 32, nls_codepage);
3124 bcc_ptr += 2 * bytes_returned;
3125 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003126 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 nls_codepage);
3128 bcc_ptr += 2 * bytes_returned;
3129 bcc_ptr += 2; /* null term version string */
3130 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003131 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 64, nls_codepage);
3133 bcc_ptr += 2 * bytes_returned;
3134 *(bcc_ptr + 1) = 0;
3135 *(bcc_ptr + 2) = 0;
3136 bcc_ptr += 2; /* null terminate network opsys string */
3137 *(bcc_ptr + 1) = 0;
3138 *(bcc_ptr + 2) = 0;
3139 bcc_ptr += 2; /* null domain */
3140 } else { /* ASCII */
3141 if (domain == NULL) {
3142 SecurityBlob->DomainName.Buffer = 0;
3143 SecurityBlob->DomainName.Length = 0;
3144 SecurityBlob->DomainName.MaximumLength = 0;
3145 } else {
Steve French77159b42007-08-31 01:10:17 +00003146 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3148 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003149 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003151 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 SecurityBlob->DomainName.Buffer =
3153 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003154 bcc_ptr += ln;
3155 SecurityBlobLength += ln;
3156 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 }
3158 if (user == NULL) {
3159 SecurityBlob->UserName.Buffer = 0;
3160 SecurityBlob->UserName.Length = 0;
3161 SecurityBlob->UserName.MaximumLength = 0;
3162 } else {
Steve French77159b42007-08-31 01:10:17 +00003163 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003165 ln = strnlen(user, 64);
3166 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003168 cpu_to_le32(SecurityBlobLength);
3169 bcc_ptr += ln;
3170 SecurityBlobLength += ln;
3171 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 }
3173 /* BB fill in our workstation name if known BB */
3174
3175 strcpy(bcc_ptr, "Linux version ");
3176 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003177 strcpy(bcc_ptr, utsname()->release);
3178 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3180 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3181 bcc_ptr++; /* null domain */
3182 *bcc_ptr = 0;
3183 }
3184 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3185 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3186 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3187 smb_buffer->smb_buf_length += count;
3188 pSMB->req.ByteCount = cpu_to_le16(count);
3189
3190 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003191 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003193/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3194 } else if ((smb_buffer_response->WordCount == 3) ||
3195 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003197 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003199 cFYI(1, (" Guest login")); /* BB Should we set anything
3200 in SesInfo struct ? */
3201/* if (SecurityBlob2->MessageType != NtLm??) {
3202 cFYI("Unexpected message type on auth response is %d"));
3203 } */
3204
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 if (ses) {
3206 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003207 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003209 /* UID left in wire format */
3210 ses->Suid = smb_buffer_response->Uid;
3211 bcc_ptr = pByteArea(smb_buffer_response);
3212 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 if ((pSMBr->resp.hdr.WordCount == 3)
3214 || ((pSMBr->resp.hdr.WordCount == 4)
3215 && (blob_len <
3216 pSMBr->resp.ByteCount))) {
3217 if (pSMBr->resp.hdr.WordCount == 4) {
3218 bcc_ptr +=
3219 blob_len;
3220 cFYI(1,
3221 ("Security Blob Length %d ",
3222 blob_len));
3223 }
3224
3225 cFYI(1,
3226 ("NTLMSSP response to Authenticate "));
3227
3228 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3229 if ((long) (bcc_ptr) % 2) {
3230 remaining_words =
3231 (BCC(smb_buffer_response)
3232 - 1) / 2;
3233 bcc_ptr++; /* Unicode strings must be word aligned */
3234 } else {
3235 remaining_words = BCC(smb_buffer_response) / 2;
3236 }
Steve French77159b42007-08-31 01:10:17 +00003237 len = UniStrnlen((wchar_t *) bcc_ptr,
3238 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239/* We look for obvious messed up bcc or strings in response so we do not go off
3240 the end since (at least) WIN2K and Windows XP have a major bug in not null
3241 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003242 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003243 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003245 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003247 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 bcc_ptr, len,
3249 nls_codepage);
3250 bcc_ptr += 2 * (len + 1);
3251 remaining_words -= len + 1;
3252 ses->serverOS[2 * len] = 0;
3253 ses->serverOS[1 + (2 * len)] = 0;
3254 if (remaining_words > 0) {
3255 len = UniStrnlen((wchar_t *)
3256 bcc_ptr,
3257 remaining_words
3258 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003259 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003261 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 GFP_KERNEL);
3263 cifs_strfromUCS_le(ses->
3264 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003265 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 bcc_ptr,
3267 len,
3268 nls_codepage);
3269 bcc_ptr += 2 * (len + 1);
3270 ses->serverNOS[2 * len] = 0;
3271 ses->serverNOS[1+(2*len)] = 0;
3272 remaining_words -= len + 1;
3273 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003274 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003276 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003277 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003279 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 (len +
3281 1),
3282 GFP_KERNEL);
3283 cifs_strfromUCS_le
3284 (ses->
3285 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003286 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 bcc_ptr, len,
3288 nls_codepage);
3289 bcc_ptr +=
3290 2 * (len + 1);
3291 ses->
3292 serverDomain[2
3293 * len]
3294 = 0;
3295 ses->
3296 serverDomain[1
3297 +
3298 (2
3299 *
3300 len)]
3301 = 0;
3302 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003303 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003304 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003305 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003306 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003309 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003310 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003311 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003312 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003313 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 }
3315 } else { /* ASCII */
3316 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003317 if (((long) bcc_ptr + len) -
3318 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003319 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003320 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003321 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003322 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 strncpy(ses->serverOS,bcc_ptr, len);
3324
3325 bcc_ptr += len;
3326 bcc_ptr[0] = 0; /* null terminate the string */
3327 bcc_ptr++;
3328
3329 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003330 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003331 ses->serverNOS = kzalloc(len+1,
3332 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003333 strncpy(ses->serverNOS,
3334 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 bcc_ptr += len;
3336 bcc_ptr[0] = 0;
3337 bcc_ptr++;
3338
3339 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003340 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003341 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003342 ses->serverDomain =
3343 kzalloc(len+1,
3344 GFP_KERNEL);
3345 strncpy(ses->serverDomain,
3346 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 bcc_ptr += len;
3348 bcc_ptr[0] = 0;
3349 bcc_ptr++;
3350 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003351 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003352 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 len));
3354 }
3355 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003356 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003357 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 }
3359 } else {
3360 cERROR(1, ("No session structure passed in."));
3361 }
3362 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003363 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 smb_buffer_response->WordCount));
3365 rc = -EIO;
3366 }
3367
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003368 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369
3370 return rc;
3371}
3372
3373int
3374CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3375 const char *tree, struct cifsTconInfo *tcon,
3376 const struct nls_table *nls_codepage)
3377{
3378 struct smb_hdr *smb_buffer;
3379 struct smb_hdr *smb_buffer_response;
3380 TCONX_REQ *pSMB;
3381 TCONX_RSP *pSMBr;
3382 unsigned char *bcc_ptr;
3383 int rc = 0;
3384 int length;
3385 __u16 count;
3386
3387 if (ses == NULL)
3388 return -EIO;
3389
3390 smb_buffer = cifs_buf_get();
3391 if (smb_buffer == NULL) {
3392 return -ENOMEM;
3393 }
3394 smb_buffer_response = smb_buffer;
3395
3396 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3397 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003398
3399 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 smb_buffer->Uid = ses->Suid;
3401 pSMB = (TCONX_REQ *) smb_buffer;
3402 pSMBr = (TCONX_RSP *) smb_buffer_response;
3403
3404 pSMB->AndXCommand = 0xFF;
3405 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003407 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003408 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003409 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003410 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003411 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003412 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003413 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003414 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3415 specified as required (when that support is added to
3416 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003417 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003418 by Samba (not sure whether other servers allow
3419 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003420#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003421 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003422 (ses->server->secType == LANMAN))
3423 calc_lanman_hash(ses, bcc_ptr);
3424 else
3425#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003426 SMBNTencrypt(ses->password,
3427 ses->server->cryptKey,
3428 bcc_ptr);
3429
Steve French7c7b25b2006-06-01 19:20:10 +00003430 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003431 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003432 /* must align unicode strings */
3433 *bcc_ptr = 0; /* null byte password */
3434 bcc_ptr++;
3435 }
Steve Frencheeac8042006-01-13 21:34:58 -08003436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437
Steve French50c2f752007-07-13 00:33:32 +00003438 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003439 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3441
3442 if (ses->capabilities & CAP_STATUS32) {
3443 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3444 }
3445 if (ses->capabilities & CAP_DFS) {
3446 smb_buffer->Flags2 |= SMBFLG2_DFS;
3447 }
3448 if (ses->capabilities & CAP_UNICODE) {
3449 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3450 length =
Steve French50c2f752007-07-13 00:33:32 +00003451 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3452 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003453 (/* server len*/ + 256 /* share len */), nls_codepage);
3454 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 bcc_ptr += 2; /* skip trailing null */
3456 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 strcpy(bcc_ptr, tree);
3458 bcc_ptr += strlen(tree) + 1;
3459 }
3460 strcpy(bcc_ptr, "?????");
3461 bcc_ptr += strlen("?????");
3462 bcc_ptr += 1;
3463 count = bcc_ptr - &pSMB->Password[0];
3464 pSMB->hdr.smb_buf_length += count;
3465 pSMB->ByteCount = cpu_to_le16(count);
3466
Steve French133672e2007-11-13 22:41:37 +00003467 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3468 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469
3470 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3471 /* above now done in SendReceive */
3472 if ((rc == 0) && (tcon != NULL)) {
3473 tcon->tidStatus = CifsGood;
3474 tcon->tid = smb_buffer_response->Tid;
3475 bcc_ptr = pByteArea(smb_buffer_response);
3476 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003477 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003478 if (length == 3) {
3479 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3480 (bcc_ptr[2] == 'C')) {
3481 cFYI(1, ("IPC connection"));
3482 tcon->ipc = 1;
3483 }
3484 } else if (length == 2) {
3485 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3486 /* the most common case */
3487 cFYI(1, ("disk share connection"));
3488 }
3489 }
Steve French50c2f752007-07-13 00:33:32 +00003490 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3492 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3493 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3494 if ((bcc_ptr + (2 * length)) -
3495 pByteArea(smb_buffer_response) <=
3496 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003497 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003499 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003500 if (tcon->nativeFileSystem)
3501 cifs_strfromUCS_le(
3502 tcon->nativeFileSystem,
3503 (__le16 *) bcc_ptr,
3504 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 bcc_ptr += 2 * length;
3506 bcc_ptr[0] = 0; /* null terminate the string */
3507 bcc_ptr[1] = 0;
3508 bcc_ptr += 2;
3509 }
Steve French50c2f752007-07-13 00:33:32 +00003510 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 } else {
3512 length = strnlen(bcc_ptr, 1024);
3513 if ((bcc_ptr + length) -
3514 pByteArea(smb_buffer_response) <=
3515 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003516 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003518 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003519 if (tcon->nativeFileSystem)
3520 strncpy(tcon->nativeFileSystem, bcc_ptr,
3521 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 }
Steve French50c2f752007-07-13 00:33:32 +00003523 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003525 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003526 (smb_buffer_response->WordCount == 7))
3527 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003528 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3529 else
3530 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3532 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003533 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 ses->ipc_tid = smb_buffer_response->Tid;
3535 }
3536
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003537 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 return rc;
3539}
3540
3541int
3542cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3543{
3544 int rc = 0;
3545 int xid;
3546 struct cifsSesInfo *ses = NULL;
3547 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003548 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
3550 xid = GetXid();
3551
3552 if (cifs_sb->tcon) {
3553 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3554 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3555 if (rc == -EBUSY) {
3556 FreeXid(xid);
3557 return 0;
3558 }
Steve French5d941ca2008-04-15 18:40:48 +00003559 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 tconInfoFree(cifs_sb->tcon);
3561 if ((ses) && (ses->server)) {
3562 /* save off task so we do not refer to ses later */
3563 cifsd_task = ses->server->tsk;
3564 cFYI(1, ("About to do SMBLogoff "));
3565 rc = CIFSSMBLogoff(xid, ses);
3566 if (rc == -EBUSY) {
3567 FreeXid(xid);
3568 return 0;
3569 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003570 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003571 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003572 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003573 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 rc = 0;
3576 } /* else - we have an smb session
3577 left on this socket do not kill cifsd */
3578 } else
3579 cFYI(1, ("No session or bad tcon"));
3580 }
Steve French50c2f752007-07-13 00:33:32 +00003581
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003583 tmp = cifs_sb->prepath;
3584 cifs_sb->prepathlen = 0;
3585 cifs_sb->prepath = NULL;
3586 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003587 if (ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 sesInfoFree(ses);
3589
3590 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003591 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003592}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593
3594int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003595 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596{
3597 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003598 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003599 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003600 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003601 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602
3603 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003604 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003606 if (rc == -EAGAIN) {
3607 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003609 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 rc = -EHOSTDOWN;
3611 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003612 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003614 if (server->tcpStatus != CifsExiting)
3615 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 else
3617 rc = -EHOSTDOWN;
3618 spin_unlock(&GlobalMid_Lock);
3619
3620 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003621 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 }
Steve French26b994f2008-08-06 05:11:33 +00003623
3624 if (rc)
3625 goto ss_err_exit;
3626
3627 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003628 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003629 if (linuxExtEnabled == 0)
3630 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003631 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003632 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003633 server->secMode, server->capabilities, server->timeAdj));
3634
Steve French26b994f2008-08-06 05:11:33 +00003635 if (experimEnabled < 2)
3636 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3637 else if (extended_security
3638 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003639 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003640 rc = -EOPNOTSUPP;
3641 } else if (extended_security
3642 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003643 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003644 cFYI(1, ("NTLMSSP sesssetup"));
3645 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3646 nls_info);
3647 if (!rc) {
3648 if (ntlmv2_flag) {
3649 char *v2_response;
3650 cFYI(1, ("more secure NTLM ver2 hash"));
3651 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3652 nls_info)) {
3653 rc = -ENOMEM;
3654 goto ss_err_exit;
3655 } else
3656 v2_response = kmalloc(16 + 64 /* blob*/,
3657 GFP_KERNEL);
3658 if (v2_response) {
3659 CalcNTLMv2_response(pSesInfo,
3660 v2_response);
3661 /* if (first_time)
3662 cifs_calculate_ntlmv2_mac_key */
3663 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 } else {
Steve French26b994f2008-08-06 05:11:33 +00003666 rc = -ENOMEM;
3667 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 }
Steve French26b994f2008-08-06 05:11:33 +00003669
3670 } else {
3671 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003672 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003673 ntlm_session_key);
3674
3675 if (first_time)
3676 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003677 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003678 ntlm_session_key,
3679 pSesInfo->password);
3680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 /* for better security the weaker lanman hash not sent
3682 in AuthSessSetup so we no longer calculate it */
3683
Steve French26b994f2008-08-06 05:11:33 +00003684 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3685 ntlm_session_key,
3686 ntlmv2_flag,
3687 nls_info);
3688 }
3689 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003690 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003691 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692
Steve French26b994f2008-08-06 05:11:33 +00003693 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003694 cifs_calculate_mac_key(&server->mac_signing_key,
3695 ntlm_session_key,
3696 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003697
Steve French26b994f2008-08-06 05:11:33 +00003698 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 }
Steve French26b994f2008-08-06 05:11:33 +00003700 if (rc) {
3701 cERROR(1, ("Send error in SessSetup = %d", rc));
3702 } else {
3703 cFYI(1, ("CIFS Session Established successfully"));
3704 pSesInfo->status = CifsGood;
3705 }
3706
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707ss_err_exit:
3708 return rc;
3709}
3710