b8e91470c27f895e8b583741cfc5d30ff7062cde
[deliverable/linux.git] / fs / cifs / cifssmb.c
1 /*
2 * fs/cifs/cifssmb.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002,2006
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly different for reconnection purposes since we never want */
28 /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifsacl.h"
41
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44 int index;
45 char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49 {LANMAN2_PROT, "\2LANMAN2.1"},
50 #endif /* weak password hashing for legacy clients */
51 {CIFS_PROT, "\2NT LM 0.12"},
52 {POSIX_PROT, "\2POSIX 2"},
53 {BAD_PROT, "\2"}
54 };
55 #else
56 static struct {
57 int index;
58 char *name;
59 } protocols[] = {
60 #ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
62 {LANMAN2_PROT, "\2LANMAN2.1"},
63 #endif /* weak password hashing for legacy clients */
64 {CIFS_PROT, "\2NT LM 0.12"},
65 {BAD_PROT, "\2"}
66 };
67 #endif
68
69 /* define the number of elements in the cifs dialect array */
70 #ifdef CONFIG_CIFS_POSIX
71 #ifdef CONFIG_CIFS_WEAK_PW_HASH
72 #define CIFS_NUM_PROT 4
73 #else
74 #define CIFS_NUM_PROT 2
75 #endif /* CIFS_WEAK_PW_HASH */
76 #else /* not posix */
77 #ifdef CONFIG_CIFS_WEAK_PW_HASH
78 #define CIFS_NUM_PROT 3
79 #else
80 #define CIFS_NUM_PROT 1
81 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
82 #endif /* CIFS_POSIX */
83
84
85 /* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
87 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
88 {
89 struct cifsFileInfo *open_file = NULL;
90 struct list_head * tmp;
91 struct list_head * tmp1;
92
93 /* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
96 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
97 if(open_file) {
98 open_file->invalidHandle = TRUE;
99 }
100 }
101 write_unlock(&GlobalSMBSeslock);
102 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103 to this tcon */
104 }
105
106 /* If the return code is zero, this function must fill in request_buf pointer */
107 static int
108 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
109 void **request_buf /* returned */)
110 {
111 int rc = 0;
112
113 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
114 check for tcp and smb session status done differently
115 for those three - in the calling routine */
116 if(tcon) {
117 if(tcon->tidStatus == CifsExiting) {
118 /* only tree disconnect, open, and write,
119 (and ulogoff which does not have tcon)
120 are allowed as we start force umount */
121 if((smb_command != SMB_COM_WRITE_ANDX) &&
122 (smb_command != SMB_COM_OPEN_ANDX) &&
123 (smb_command != SMB_COM_TREE_DISCONNECT)) {
124 cFYI(1,("can not send cmd %d while umounting",
125 smb_command));
126 return -ENODEV;
127 }
128 }
129 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
130 (tcon->ses->server)){
131 struct nls_table *nls_codepage;
132 /* Give Demultiplex thread up to 10 seconds to
133 reconnect, should be greater than cifs socket
134 timeout which is 7 seconds */
135 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
137 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
138 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
139 /* on "soft" mounts we wait once */
140 if((tcon->retry == FALSE) ||
141 (tcon->ses->status == CifsExiting)) {
142 cFYI(1,("gave up waiting on reconnect in smb_init"));
143 return -EHOSTDOWN;
144 } /* else "hard" mount - keep retrying
145 until process is killed or server
146 comes back on-line */
147 } else /* TCP session is reestablished now */
148 break;
149
150 }
151
152 nls_codepage = load_nls_default();
153 /* need to prevent multiple threads trying to
154 simultaneously reconnect the same SMB session */
155 down(&tcon->ses->sesSem);
156 if(tcon->ses->status == CifsNeedReconnect)
157 rc = cifs_setup_session(0, tcon->ses,
158 nls_codepage);
159 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
160 mark_open_files_invalid(tcon);
161 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
162 tcon, nls_codepage);
163 up(&tcon->ses->sesSem);
164 /* tell server which Unix caps we support */
165 if (tcon->ses->capabilities & CAP_UNIX)
166 reset_cifs_unix_caps(0 /* no xid */,
167 tcon,
168 NULL /* we do not know sb */,
169 NULL /* no vol info */);
170 /* BB FIXME add code to check if wsize needs
171 update due to negotiated smb buffer size
172 shrinking */
173 if(rc == 0)
174 atomic_inc(&tconInfoReconnectCount);
175
176 cFYI(1, ("reconnect tcon rc = %d", rc));
177 /* Removed call to reopen open files here -
178 it is safer (and faster) to reopen files
179 one at a time as needed in read and write */
180
181 /* Check if handle based operation so we
182 know whether we can continue or not without
183 returning to caller to reset file handle */
184 switch(smb_command) {
185 case SMB_COM_READ_ANDX:
186 case SMB_COM_WRITE_ANDX:
187 case SMB_COM_CLOSE:
188 case SMB_COM_FIND_CLOSE2:
189 case SMB_COM_LOCKING_ANDX: {
190 unload_nls(nls_codepage);
191 return -EAGAIN;
192 }
193 }
194 } else {
195 up(&tcon->ses->sesSem);
196 }
197 unload_nls(nls_codepage);
198
199 } else {
200 return -EIO;
201 }
202 }
203 if(rc)
204 return rc;
205
206 *request_buf = cifs_small_buf_get();
207 if (*request_buf == NULL) {
208 /* BB should we add a retry in here if not a writepage? */
209 return -ENOMEM;
210 }
211
212 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
213
214 if(tcon != NULL)
215 cifs_stats_inc(&tcon->num_smbs_sent);
216
217 return rc;
218 }
219
220 int
221 small_smb_init_no_tc(const int smb_command, const int wct,
222 struct cifsSesInfo *ses, void **request_buf)
223 {
224 int rc;
225 struct smb_hdr * buffer;
226
227 rc = small_smb_init(smb_command, wct, NULL, request_buf);
228 if(rc)
229 return rc;
230
231 buffer = (struct smb_hdr *)*request_buf;
232 buffer->Mid = GetNextMid(ses->server);
233 if (ses->capabilities & CAP_UNICODE)
234 buffer->Flags2 |= SMBFLG2_UNICODE;
235 if (ses->capabilities & CAP_STATUS32)
236 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
237
238 /* uid, tid can stay at zero as set in header assemble */
239
240 /* BB add support for turning on the signing when
241 this function is used after 1st of session setup requests */
242
243 return rc;
244 }
245
246 /* If the return code is zero, this function must fill in request_buf pointer */
247 static int
248 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
249 void **request_buf /* returned */ ,
250 void **response_buf /* returned */ )
251 {
252 int rc = 0;
253
254 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
255 check for tcp and smb session status done differently
256 for those three - in the calling routine */
257 if(tcon) {
258 if(tcon->tidStatus == CifsExiting) {
259 /* only tree disconnect, open, and write,
260 (and ulogoff which does not have tcon)
261 are allowed as we start force umount */
262 if((smb_command != SMB_COM_WRITE_ANDX) &&
263 (smb_command != SMB_COM_OPEN_ANDX) &&
264 (smb_command != SMB_COM_TREE_DISCONNECT)) {
265 cFYI(1,("can not send cmd %d while umounting",
266 smb_command));
267 return -ENODEV;
268 }
269 }
270
271 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
272 (tcon->ses->server)){
273 struct nls_table *nls_codepage;
274 /* Give Demultiplex thread up to 10 seconds to
275 reconnect, should be greater than cifs socket
276 timeout which is 7 seconds */
277 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
278 wait_event_interruptible_timeout(tcon->ses->server->response_q,
279 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
280 if(tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
282 /* on "soft" mounts we wait once */
283 if((tcon->retry == FALSE) ||
284 (tcon->ses->status == CifsExiting)) {
285 cFYI(1,("gave up waiting on reconnect in smb_init"));
286 return -EHOSTDOWN;
287 } /* else "hard" mount - keep retrying
288 until process is killed or server
289 comes on-line */
290 } else /* TCP session is reestablished now */
291 break;
292
293 }
294
295 nls_codepage = load_nls_default();
296 /* need to prevent multiple threads trying to
297 simultaneously reconnect the same SMB session */
298 down(&tcon->ses->sesSem);
299 if(tcon->ses->status == CifsNeedReconnect)
300 rc = cifs_setup_session(0, tcon->ses,
301 nls_codepage);
302 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
303 mark_open_files_invalid(tcon);
304 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
305 tcon, nls_codepage);
306 up(&tcon->ses->sesSem);
307 /* tell server which Unix caps we support */
308 if (tcon->ses->capabilities & CAP_UNIX)
309 reset_cifs_unix_caps(0 /* no xid */,
310 tcon,
311 NULL /* do not know sb */,
312 NULL /* no vol info */);
313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
316 if(rc == 0)
317 atomic_inc(&tconInfoReconnectCount);
318
319 cFYI(1, ("reconnect tcon rc = %d", rc));
320 /* Removed call to reopen open files here -
321 it is safer (and faster) to reopen files
322 one at a time as needed in read and write */
323
324 /* Check if handle based operation so we
325 know whether we can continue or not without
326 returning to caller to reset file handle */
327 switch(smb_command) {
328 case SMB_COM_READ_ANDX:
329 case SMB_COM_WRITE_ANDX:
330 case SMB_COM_CLOSE:
331 case SMB_COM_FIND_CLOSE2:
332 case SMB_COM_LOCKING_ANDX: {
333 unload_nls(nls_codepage);
334 return -EAGAIN;
335 }
336 }
337 } else {
338 up(&tcon->ses->sesSem);
339 }
340 unload_nls(nls_codepage);
341
342 } else {
343 return -EIO;
344 }
345 }
346 if(rc)
347 return rc;
348
349 *request_buf = cifs_buf_get();
350 if (*request_buf == NULL) {
351 /* BB should we add a retry in here if not a writepage? */
352 return -ENOMEM;
353 }
354 /* Although the original thought was we needed the response buf for */
355 /* potential retries of smb operations it turns out we can determine */
356 /* from the mid flags when the request buffer can be resent without */
357 /* having to use a second distinct buffer for the response */
358 if(response_buf)
359 *response_buf = *request_buf;
360
361 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
362 wct /*wct */ );
363
364 if(tcon != NULL)
365 cifs_stats_inc(&tcon->num_smbs_sent);
366
367 return rc;
368 }
369
370 static int validate_t2(struct smb_t2_rsp * pSMB)
371 {
372 int rc = -EINVAL;
373 int total_size;
374 char * pBCC;
375
376 /* check for plausible wct, bcc and t2 data and parm sizes */
377 /* check for parm and data offset going beyond end of smb */
378 if(pSMB->hdr.WordCount >= 10) {
379 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
380 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
381 /* check that bcc is at least as big as parms + data */
382 /* check that bcc is less than negotiated smb buffer */
383 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
384 if(total_size < 512) {
385 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
386 /* BCC le converted in SendReceive */
387 pBCC = (pSMB->hdr.WordCount * 2) +
388 sizeof(struct smb_hdr) +
389 (char *)pSMB;
390 if((total_size <= (*(u16 *)pBCC)) &&
391 (total_size <
392 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
393 return 0;
394 }
395
396 }
397 }
398 }
399 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
400 sizeof(struct smb_t2_rsp) + 16);
401 return rc;
402 }
403 int
404 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
405 {
406 NEGOTIATE_REQ *pSMB;
407 NEGOTIATE_RSP *pSMBr;
408 int rc = 0;
409 int bytes_returned;
410 int i;
411 struct TCP_Server_Info * server;
412 u16 count;
413 unsigned int secFlags;
414 u16 dialect;
415
416 if(ses->server)
417 server = ses->server;
418 else {
419 rc = -EIO;
420 return rc;
421 }
422 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
423 (void **) &pSMB, (void **) &pSMBr);
424 if (rc)
425 return rc;
426
427 /* if any of auth flags (ie not sign or seal) are overriden use them */
428 if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
429 secFlags = ses->overrideSecFlg;
430 else /* if override flags set only sign/seal OR them with global auth */
431 secFlags = extended_security | ses->overrideSecFlg;
432
433 cFYI(1,("secFlags 0x%x",secFlags));
434
435 pSMB->hdr.Mid = GetNextMid(server);
436 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
437 if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
438 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
439
440 count = 0;
441 for(i=0;i<CIFS_NUM_PROT;i++) {
442 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
443 count += strlen(protocols[i].name) + 1;
444 /* null at end of source and target buffers anyway */
445 }
446 pSMB->hdr.smb_buf_length += count;
447 pSMB->ByteCount = cpu_to_le16(count);
448
449 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
451 if (rc != 0)
452 goto neg_err_exit;
453
454 dialect = le16_to_cpu(pSMBr->DialectIndex);
455 cFYI(1,("Dialect: %d", dialect));
456 /* Check wct = 1 error case */
457 if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
458 /* core returns wct = 1, but we do not ask for core - otherwise
459 small wct just comes when dialect index is -1 indicating we
460 could not negotiate a common dialect */
461 rc = -EOPNOTSUPP;
462 goto neg_err_exit;
463 #ifdef CONFIG_CIFS_WEAK_PW_HASH
464 } else if((pSMBr->hdr.WordCount == 13)
465 && ((dialect == LANMAN_PROT)
466 || (dialect == LANMAN2_PROT))) {
467 __s16 tmp;
468 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
469
470 if((secFlags & CIFSSEC_MAY_LANMAN) ||
471 (secFlags & CIFSSEC_MAY_PLNTXT))
472 server->secType = LANMAN;
473 else {
474 cERROR(1, ("mount failed weak security disabled"
475 " in /proc/fs/cifs/SecurityFlags"));
476 rc = -EOPNOTSUPP;
477 goto neg_err_exit;
478 }
479 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
480 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
481 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
482 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
483 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
484 /* even though we do not use raw we might as well set this
485 accurately, in case we ever find a need for it */
486 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
487 server->maxRw = 0xFF00;
488 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
489 } else {
490 server->maxRw = 0;/* we do not need to use raw anyway */
491 server->capabilities = CAP_MPX_MODE;
492 }
493 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
494 if (tmp == -1) {
495 /* OS/2 often does not set timezone therefore
496 * we must use server time to calc time zone.
497 * Could deviate slightly from the right zone.
498 * Smallest defined timezone difference is 15 minutes
499 * (i.e. Nepal). Rounding up/down is done to match
500 * this requirement.
501 */
502 int val, seconds, remain, result;
503 struct timespec ts, utc;
504 utc = CURRENT_TIME;
505 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
506 le16_to_cpu(rsp->SrvTime.Time));
507 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
508 (int)ts.tv_sec, (int)utc.tv_sec,
509 (int)(utc.tv_sec - ts.tv_sec)));
510 val = (int)(utc.tv_sec - ts.tv_sec);
511 seconds = val < 0 ? -val : val;
512 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
513 remain = seconds % MIN_TZ_ADJ;
514 if(remain >= (MIN_TZ_ADJ / 2))
515 result += MIN_TZ_ADJ;
516 if(val < 0)
517 result = - result;
518 server->timeAdj = result;
519 } else {
520 server->timeAdj = (int)tmp;
521 server->timeAdj *= 60; /* also in seconds */
522 }
523 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
524
525
526 /* BB get server time for time conversions and add
527 code to use it and timezone since this is not UTC */
528
529 if (rsp->EncryptionKeyLength ==
530 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
531 memcpy(server->cryptKey, rsp->EncryptionKey,
532 CIFS_CRYPTO_KEY_SIZE);
533 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
534 rc = -EIO; /* need cryptkey unless plain text */
535 goto neg_err_exit;
536 }
537
538 cFYI(1,("LANMAN negotiated"));
539 /* we will not end up setting signing flags - as no signing
540 was in LANMAN and server did not return the flags on */
541 goto signing_check;
542 #else /* weak security disabled */
543 } else if(pSMBr->hdr.WordCount == 13) {
544 cERROR(1,("mount failed, cifs module not built "
545 "with CIFS_WEAK_PW_HASH support"));
546 rc = -EOPNOTSUPP;
547 #endif /* WEAK_PW_HASH */
548 goto neg_err_exit;
549 } else if(pSMBr->hdr.WordCount != 17) {
550 /* unknown wct */
551 rc = -EOPNOTSUPP;
552 goto neg_err_exit;
553 }
554 /* else wct == 17 NTLM */
555 server->secMode = pSMBr->SecurityMode;
556 if((server->secMode & SECMODE_USER) == 0)
557 cFYI(1,("share mode security"));
558
559 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
560 #ifdef CONFIG_CIFS_WEAK_PW_HASH
561 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
562 #endif /* CIFS_WEAK_PW_HASH */
563 cERROR(1,("Server requests plain text password"
564 " but client support disabled"));
565
566 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
567 server->secType = NTLMv2;
568 else if(secFlags & CIFSSEC_MAY_NTLM)
569 server->secType = NTLM;
570 else if(secFlags & CIFSSEC_MAY_NTLMV2)
571 server->secType = NTLMv2;
572 /* else krb5 ... any others ... */
573
574 /* one byte, so no need to convert this or EncryptionKeyLen from
575 little endian */
576 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
577 /* probably no need to store and check maxvcs */
578 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
579 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
580 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
581 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
582 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
583 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
584 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
585 server->timeAdj *= 60;
586 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
587 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
588 CIFS_CRYPTO_KEY_SIZE);
589 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
590 && (pSMBr->EncryptionKeyLength == 0)) {
591 /* decode security blob */
592 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
593 rc = -EIO; /* no crypt key only if plain text pwd */
594 goto neg_err_exit;
595 }
596
597 /* BB might be helpful to save off the domain of server here */
598
599 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
600 (server->capabilities & CAP_EXTENDED_SECURITY)) {
601 count = pSMBr->ByteCount;
602 if (count < 16)
603 rc = -EIO;
604 else if (count == 16) {
605 server->secType = RawNTLMSSP;
606 if (server->socketUseCount.counter > 1) {
607 if (memcmp(server->server_GUID,
608 pSMBr->u.extended_response.
609 GUID, 16) != 0) {
610 cFYI(1, ("server UID changed"));
611 memcpy(server->server_GUID,
612 pSMBr->u.extended_response.GUID,
613 16);
614 }
615 } else
616 memcpy(server->server_GUID,
617 pSMBr->u.extended_response.GUID, 16);
618 } else {
619 rc = decode_negTokenInit(pSMBr->u.extended_response.
620 SecurityBlob,
621 count - 16,
622 &server->secType);
623 if(rc == 1) {
624 /* BB Need to fill struct for sessetup here */
625 rc = -EOPNOTSUPP;
626 } else {
627 rc = -EINVAL;
628 }
629 }
630 } else
631 server->capabilities &= ~CAP_EXTENDED_SECURITY;
632
633 #ifdef CONFIG_CIFS_WEAK_PW_HASH
634 signing_check:
635 #endif
636 if(sign_CIFS_PDUs == FALSE) {
637 if(server->secMode & SECMODE_SIGN_REQUIRED)
638 cERROR(1,("Server requires "
639 "/proc/fs/cifs/PacketSigningEnabled to be on"));
640 server->secMode &=
641 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
642 } else if(sign_CIFS_PDUs == 1) {
643 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
644 server->secMode &=
645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
646 } else if(sign_CIFS_PDUs == 2) {
647 if((server->secMode &
648 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
649 cERROR(1,("signing required but server lacks support"));
650 }
651 }
652 neg_err_exit:
653 cifs_buf_release(pSMB);
654
655 cFYI(1,("negprot rc %d",rc));
656 return rc;
657 }
658
659 int
660 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
661 {
662 struct smb_hdr *smb_buffer;
663 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
664 int rc = 0;
665 int length;
666
667 cFYI(1, ("In tree disconnect"));
668 /*
669 * If last user of the connection and
670 * connection alive - disconnect it
671 * If this is the last connection on the server session disconnect it
672 * (and inside session disconnect we should check if tcp socket needs
673 * to be freed and kernel thread woken up).
674 */
675 if (tcon)
676 down(&tcon->tconSem);
677 else
678 return -EIO;
679
680 atomic_dec(&tcon->useCount);
681 if (atomic_read(&tcon->useCount) > 0) {
682 up(&tcon->tconSem);
683 return -EBUSY;
684 }
685
686 /* No need to return error on this operation if tid invalidated and
687 closed on server already e.g. due to tcp session crashing */
688 if(tcon->tidStatus == CifsNeedReconnect) {
689 up(&tcon->tconSem);
690 return 0;
691 }
692
693 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
694 up(&tcon->tconSem);
695 return -EIO;
696 }
697 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
698 (void **)&smb_buffer);
699 if (rc) {
700 up(&tcon->tconSem);
701 return rc;
702 } else {
703 smb_buffer_response = smb_buffer; /* BB removeme BB */
704 }
705 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
706 &length, 0);
707 if (rc)
708 cFYI(1, ("Tree disconnect failed %d", rc));
709
710 if (smb_buffer)
711 cifs_small_buf_release(smb_buffer);
712 up(&tcon->tconSem);
713
714 /* No need to return error on this operation if tid invalidated and
715 closed on server already e.g. due to tcp session crashing */
716 if (rc == -EAGAIN)
717 rc = 0;
718
719 return rc;
720 }
721
722 int
723 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
724 {
725 struct smb_hdr *smb_buffer_response;
726 LOGOFF_ANDX_REQ *pSMB;
727 int rc = 0;
728 int length;
729
730 cFYI(1, ("In SMBLogoff for session disconnect"));
731 if (ses)
732 down(&ses->sesSem);
733 else
734 return -EIO;
735
736 atomic_dec(&ses->inUse);
737 if (atomic_read(&ses->inUse) > 0) {
738 up(&ses->sesSem);
739 return -EBUSY;
740 }
741 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
742 if (rc) {
743 up(&ses->sesSem);
744 return rc;
745 }
746
747 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
748
749 if(ses->server) {
750 pSMB->hdr.Mid = GetNextMid(ses->server);
751
752 if(ses->server->secMode &
753 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
754 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
755 }
756
757 pSMB->hdr.Uid = ses->Suid;
758
759 pSMB->AndXCommand = 0xFF;
760 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
761 smb_buffer_response, &length, 0);
762 if (ses->server) {
763 atomic_dec(&ses->server->socketUseCount);
764 if (atomic_read(&ses->server->socketUseCount) == 0) {
765 spin_lock(&GlobalMid_Lock);
766 ses->server->tcpStatus = CifsExiting;
767 spin_unlock(&GlobalMid_Lock);
768 rc = -ESHUTDOWN;
769 }
770 }
771 up(&ses->sesSem);
772 cifs_small_buf_release(pSMB);
773
774 /* if session dead then we do not need to do ulogoff,
775 since server closed smb session, no sense reporting
776 error */
777 if (rc == -EAGAIN)
778 rc = 0;
779 return rc;
780 }
781
782 int
783 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
784 const struct nls_table *nls_codepage, int remap)
785 {
786 DELETE_FILE_REQ *pSMB = NULL;
787 DELETE_FILE_RSP *pSMBr = NULL;
788 int rc = 0;
789 int bytes_returned;
790 int name_len;
791
792 DelFileRetry:
793 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
794 (void **) &pSMBr);
795 if (rc)
796 return rc;
797
798 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
799 name_len =
800 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
801 PATH_MAX, nls_codepage, remap);
802 name_len++; /* trailing null */
803 name_len *= 2;
804 } else { /* BB improve check for buffer overruns BB */
805 name_len = strnlen(fileName, PATH_MAX);
806 name_len++; /* trailing null */
807 strncpy(pSMB->fileName, fileName, name_len);
808 }
809 pSMB->SearchAttributes =
810 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
811 pSMB->BufferFormat = 0x04;
812 pSMB->hdr.smb_buf_length += name_len + 1;
813 pSMB->ByteCount = cpu_to_le16(name_len + 1);
814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
816 cifs_stats_inc(&tcon->num_deletes);
817 if (rc) {
818 cFYI(1, ("Error in RMFile = %d", rc));
819 }
820
821 cifs_buf_release(pSMB);
822 if (rc == -EAGAIN)
823 goto DelFileRetry;
824
825 return rc;
826 }
827
828 int
829 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
830 const struct nls_table *nls_codepage, int remap)
831 {
832 DELETE_DIRECTORY_REQ *pSMB = NULL;
833 DELETE_DIRECTORY_RSP *pSMBr = NULL;
834 int rc = 0;
835 int bytes_returned;
836 int name_len;
837
838 cFYI(1, ("In CIFSSMBRmDir"));
839 RmDirRetry:
840 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
841 (void **) &pSMBr);
842 if (rc)
843 return rc;
844
845 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
846 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
847 PATH_MAX, nls_codepage, remap);
848 name_len++; /* trailing null */
849 name_len *= 2;
850 } else { /* BB improve check for buffer overruns BB */
851 name_len = strnlen(dirName, PATH_MAX);
852 name_len++; /* trailing null */
853 strncpy(pSMB->DirName, dirName, name_len);
854 }
855
856 pSMB->BufferFormat = 0x04;
857 pSMB->hdr.smb_buf_length += name_len + 1;
858 pSMB->ByteCount = cpu_to_le16(name_len + 1);
859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
861 cifs_stats_inc(&tcon->num_rmdirs);
862 if (rc) {
863 cFYI(1, ("Error in RMDir = %d", rc));
864 }
865
866 cifs_buf_release(pSMB);
867 if (rc == -EAGAIN)
868 goto RmDirRetry;
869 return rc;
870 }
871
872 int
873 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
874 const char *name, const struct nls_table *nls_codepage, int remap)
875 {
876 int rc = 0;
877 CREATE_DIRECTORY_REQ *pSMB = NULL;
878 CREATE_DIRECTORY_RSP *pSMBr = NULL;
879 int bytes_returned;
880 int name_len;
881
882 cFYI(1, ("In CIFSSMBMkDir"));
883 MkDirRetry:
884 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
885 (void **) &pSMBr);
886 if (rc)
887 return rc;
888
889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
890 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
891 PATH_MAX, nls_codepage, remap);
892 name_len++; /* trailing null */
893 name_len *= 2;
894 } else { /* BB improve check for buffer overruns BB */
895 name_len = strnlen(name, PATH_MAX);
896 name_len++; /* trailing null */
897 strncpy(pSMB->DirName, name, name_len);
898 }
899
900 pSMB->BufferFormat = 0x04;
901 pSMB->hdr.smb_buf_length += name_len + 1;
902 pSMB->ByteCount = cpu_to_le16(name_len + 1);
903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
905 cifs_stats_inc(&tcon->num_mkdirs);
906 if (rc) {
907 cFYI(1, ("Error in Mkdir = %d", rc));
908 }
909
910 cifs_buf_release(pSMB);
911 if (rc == -EAGAIN)
912 goto MkDirRetry;
913 return rc;
914 }
915
916 static __u16 convert_disposition(int disposition)
917 {
918 __u16 ofun = 0;
919
920 switch (disposition) {
921 case FILE_SUPERSEDE:
922 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
923 break;
924 case FILE_OPEN:
925 ofun = SMBOPEN_OAPPEND;
926 break;
927 case FILE_CREATE:
928 ofun = SMBOPEN_OCREATE;
929 break;
930 case FILE_OPEN_IF:
931 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
932 break;
933 case FILE_OVERWRITE:
934 ofun = SMBOPEN_OTRUNC;
935 break;
936 case FILE_OVERWRITE_IF:
937 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
938 break;
939 default:
940 cFYI(1,("unknown disposition %d",disposition));
941 ofun = SMBOPEN_OAPPEND; /* regular open */
942 }
943 return ofun;
944 }
945
946 int
947 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
948 const char *fileName, const int openDisposition,
949 const int access_flags, const int create_options, __u16 * netfid,
950 int *pOplock, FILE_ALL_INFO * pfile_info,
951 const struct nls_table *nls_codepage, int remap)
952 {
953 int rc = -EACCES;
954 OPENX_REQ *pSMB = NULL;
955 OPENX_RSP *pSMBr = NULL;
956 int bytes_returned;
957 int name_len;
958 __u16 count;
959
960 OldOpenRetry:
961 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
962 (void **) &pSMBr);
963 if (rc)
964 return rc;
965
966 pSMB->AndXCommand = 0xFF; /* none */
967
968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
969 count = 1; /* account for one byte pad to word boundary */
970 name_len =
971 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
972 fileName, PATH_MAX, nls_codepage, remap);
973 name_len++; /* trailing null */
974 name_len *= 2;
975 } else { /* BB improve check for buffer overruns BB */
976 count = 0; /* no pad */
977 name_len = strnlen(fileName, PATH_MAX);
978 name_len++; /* trailing null */
979 strncpy(pSMB->fileName, fileName, name_len);
980 }
981 if (*pOplock & REQ_OPLOCK)
982 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
983 else if (*pOplock & REQ_BATCHOPLOCK) {
984 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
985 }
986 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
987 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
988 /* 0 = read
989 1 = write
990 2 = rw
991 3 = execute
992 */
993 pSMB->Mode = cpu_to_le16(2);
994 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
995 /* set file as system file if special file such
996 as fifo and server expecting SFU style and
997 no Unix extensions */
998
999 if(create_options & CREATE_OPTION_SPECIAL)
1000 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1001 else
1002 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
1003
1004 /* if ((omode & S_IWUGO) == 0)
1005 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1006 /* Above line causes problems due to vfs splitting create into two
1007 pieces - need to set mode after file created not while it is
1008 being created */
1009
1010 /* BB FIXME BB */
1011 /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
1012 /* BB FIXME END BB */
1013
1014 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1015 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1016 count += name_len;
1017 pSMB->hdr.smb_buf_length += count;
1018
1019 pSMB->ByteCount = cpu_to_le16(count);
1020 /* long_op set to 1 to allow for oplock break timeouts */
1021 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1022 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1023 cifs_stats_inc(&tcon->num_opens);
1024 if (rc) {
1025 cFYI(1, ("Error in Open = %d", rc));
1026 } else {
1027 /* BB verify if wct == 15 */
1028
1029 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1030
1031 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1032 /* Let caller know file was created so we can set the mode. */
1033 /* Do we care about the CreateAction in any other cases? */
1034 /* BB FIXME BB */
1035 /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1036 *pOplock |= CIFS_CREATE_ACTION; */
1037 /* BB FIXME END */
1038
1039 if(pfile_info) {
1040 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1041 pfile_info->LastAccessTime = 0; /* BB fixme */
1042 pfile_info->LastWriteTime = 0; /* BB fixme */
1043 pfile_info->ChangeTime = 0; /* BB fixme */
1044 pfile_info->Attributes =
1045 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1046 /* the file_info buf is endian converted by caller */
1047 pfile_info->AllocationSize =
1048 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1049 pfile_info->EndOfFile = pfile_info->AllocationSize;
1050 pfile_info->NumberOfLinks = cpu_to_le32(1);
1051 }
1052 }
1053
1054 cifs_buf_release(pSMB);
1055 if (rc == -EAGAIN)
1056 goto OldOpenRetry;
1057 return rc;
1058 }
1059
1060 int
1061 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1062 const char *fileName, const int openDisposition,
1063 const int access_flags, const int create_options, __u16 * netfid,
1064 int *pOplock, FILE_ALL_INFO * pfile_info,
1065 const struct nls_table *nls_codepage, int remap)
1066 {
1067 int rc = -EACCES;
1068 OPEN_REQ *pSMB = NULL;
1069 OPEN_RSP *pSMBr = NULL;
1070 int bytes_returned;
1071 int name_len;
1072 __u16 count;
1073
1074 openRetry:
1075 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1076 (void **) &pSMBr);
1077 if (rc)
1078 return rc;
1079
1080 pSMB->AndXCommand = 0xFF; /* none */
1081
1082 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1083 count = 1; /* account for one byte pad to word boundary */
1084 name_len =
1085 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1086 fileName, PATH_MAX, nls_codepage, remap);
1087 name_len++; /* trailing null */
1088 name_len *= 2;
1089 pSMB->NameLength = cpu_to_le16(name_len);
1090 } else { /* BB improve check for buffer overruns BB */
1091 count = 0; /* no pad */
1092 name_len = strnlen(fileName, PATH_MAX);
1093 name_len++; /* trailing null */
1094 pSMB->NameLength = cpu_to_le16(name_len);
1095 strncpy(pSMB->fileName, fileName, name_len);
1096 }
1097 if (*pOplock & REQ_OPLOCK)
1098 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1099 else if (*pOplock & REQ_BATCHOPLOCK) {
1100 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1101 }
1102 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1103 pSMB->AllocationSize = 0;
1104 /* set file as system file if special file such
1105 as fifo and server expecting SFU style and
1106 no Unix extensions */
1107 if(create_options & CREATE_OPTION_SPECIAL)
1108 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1109 else
1110 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1111 /* XP does not handle ATTR_POSIX_SEMANTICS */
1112 /* but it helps speed up case sensitive checks for other
1113 servers such as Samba */
1114 if (tcon->ses->capabilities & CAP_UNIX)
1115 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1116
1117 /* if ((omode & S_IWUGO) == 0)
1118 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1119 /* Above line causes problems due to vfs splitting create into two
1120 pieces - need to set mode after file created not while it is
1121 being created */
1122 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1123 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1124 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1125 /* BB Expirement with various impersonation levels and verify */
1126 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1127 pSMB->SecurityFlags =
1128 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1129
1130 count += name_len;
1131 pSMB->hdr.smb_buf_length += count;
1132
1133 pSMB->ByteCount = cpu_to_le16(count);
1134 /* long_op set to 1 to allow for oplock break timeouts */
1135 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1136 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1137 cifs_stats_inc(&tcon->num_opens);
1138 if (rc) {
1139 cFYI(1, ("Error in Open = %d", rc));
1140 } else {
1141 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1142 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1143 /* Let caller know file was created so we can set the mode. */
1144 /* Do we care about the CreateAction in any other cases? */
1145 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1146 *pOplock |= CIFS_CREATE_ACTION;
1147 if(pfile_info) {
1148 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1149 36 /* CreationTime to Attributes */);
1150 /* the file_info buf is endian converted by caller */
1151 pfile_info->AllocationSize = pSMBr->AllocationSize;
1152 pfile_info->EndOfFile = pSMBr->EndOfFile;
1153 pfile_info->NumberOfLinks = cpu_to_le32(1);
1154 }
1155 }
1156
1157 cifs_buf_release(pSMB);
1158 if (rc == -EAGAIN)
1159 goto openRetry;
1160 return rc;
1161 }
1162
1163 int
1164 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
1165 const int netfid, const unsigned int count,
1166 const __u64 lseek, unsigned int *nbytes, char **buf,
1167 int * pbuf_type)
1168 {
1169 int rc = -EACCES;
1170 READ_REQ *pSMB = NULL;
1171 READ_RSP *pSMBr = NULL;
1172 char *pReadData = NULL;
1173 int wct;
1174 int resp_buf_type = 0;
1175 struct kvec iov[1];
1176
1177 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
1178 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1179 wct = 12;
1180 else
1181 wct = 10; /* old style read */
1182
1183 *nbytes = 0;
1184 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1185 if (rc)
1186 return rc;
1187
1188 /* tcon and ses pointer are checked in smb_init */
1189 if (tcon->ses->server == NULL)
1190 return -ECONNABORTED;
1191
1192 pSMB->AndXCommand = 0xFF; /* none */
1193 pSMB->Fid = netfid;
1194 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1195 if(wct == 12)
1196 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1197 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1198 return -EIO;
1199
1200 pSMB->Remaining = 0;
1201 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1202 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1203 if(wct == 12)
1204 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1205 else {
1206 /* old style read */
1207 struct smb_com_readx_req * pSMBW =
1208 (struct smb_com_readx_req *)pSMB;
1209 pSMBW->ByteCount = 0;
1210 }
1211
1212 iov[0].iov_base = (char *)pSMB;
1213 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1214 rc = SendReceive2(xid, tcon->ses, iov,
1215 1 /* num iovecs */,
1216 &resp_buf_type, 0);
1217 cifs_stats_inc(&tcon->num_reads);
1218 pSMBr = (READ_RSP *)iov[0].iov_base;
1219 if (rc) {
1220 cERROR(1, ("Send error in read = %d", rc));
1221 } else {
1222 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1223 data_length = data_length << 16;
1224 data_length += le16_to_cpu(pSMBr->DataLength);
1225 *nbytes = data_length;
1226
1227 /*check that DataLength would not go beyond end of SMB */
1228 if ((data_length > CIFSMaxBufSize)
1229 || (data_length > count)) {
1230 cFYI(1,("bad length %d for count %d",data_length,count));
1231 rc = -EIO;
1232 *nbytes = 0;
1233 } else {
1234 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1235 le16_to_cpu(pSMBr->DataOffset);
1236 /* if(rc = copy_to_user(buf, pReadData, data_length)) {
1237 cERROR(1,("Faulting on read rc = %d",rc));
1238 rc = -EFAULT;
1239 }*/ /* can not use copy_to_user when using page cache*/
1240 if(*buf)
1241 memcpy(*buf,pReadData,data_length);
1242 }
1243 }
1244
1245 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1246 if(*buf) {
1247 if(resp_buf_type == CIFS_SMALL_BUFFER)
1248 cifs_small_buf_release(iov[0].iov_base);
1249 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1250 cifs_buf_release(iov[0].iov_base);
1251 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1252 /* return buffer to caller to free */
1253 *buf = iov[0].iov_base;
1254 if(resp_buf_type == CIFS_SMALL_BUFFER)
1255 *pbuf_type = CIFS_SMALL_BUFFER;
1256 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1257 *pbuf_type = CIFS_LARGE_BUFFER;
1258 } /* else no valid buffer on return - leave as null */
1259
1260 /* Note: On -EAGAIN error only caller can retry on handle based calls
1261 since file handle passed in no longer valid */
1262 return rc;
1263 }
1264
1265
1266 int
1267 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1268 const int netfid, const unsigned int count,
1269 const __u64 offset, unsigned int *nbytes, const char *buf,
1270 const char __user * ubuf, const int long_op)
1271 {
1272 int rc = -EACCES;
1273 WRITE_REQ *pSMB = NULL;
1274 WRITE_RSP *pSMBr = NULL;
1275 int bytes_returned, wct;
1276 __u32 bytes_sent;
1277 __u16 byte_count;
1278
1279 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1280 if(tcon->ses == NULL)
1281 return -ECONNABORTED;
1282
1283 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1284 wct = 14;
1285 else
1286 wct = 12;
1287
1288 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1289 (void **) &pSMBr);
1290 if (rc)
1291 return rc;
1292 /* tcon and ses pointer are checked in smb_init */
1293 if (tcon->ses->server == NULL)
1294 return -ECONNABORTED;
1295
1296 pSMB->AndXCommand = 0xFF; /* none */
1297 pSMB->Fid = netfid;
1298 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1299 if(wct == 14)
1300 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1301 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1302 return -EIO;
1303
1304 pSMB->Reserved = 0xFFFFFFFF;
1305 pSMB->WriteMode = 0;
1306 pSMB->Remaining = 0;
1307
1308 /* Can increase buffer size if buffer is big enough in some cases - ie we
1309 can send more if LARGE_WRITE_X capability returned by the server and if
1310 our buffer is big enough or if we convert to iovecs on socket writes
1311 and eliminate the copy to the CIFS buffer */
1312 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1313 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1314 } else {
1315 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1316 & ~0xFF;
1317 }
1318
1319 if (bytes_sent > count)
1320 bytes_sent = count;
1321 pSMB->DataOffset =
1322 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1323 if(buf)
1324 memcpy(pSMB->Data,buf,bytes_sent);
1325 else if(ubuf) {
1326 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1327 cifs_buf_release(pSMB);
1328 return -EFAULT;
1329 }
1330 } else if (count != 0) {
1331 /* No buffer */
1332 cifs_buf_release(pSMB);
1333 return -EINVAL;
1334 } /* else setting file size with write of zero bytes */
1335 if(wct == 14)
1336 byte_count = bytes_sent + 1; /* pad */
1337 else /* wct == 12 */ {
1338 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1339 }
1340 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1341 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1342 pSMB->hdr.smb_buf_length += byte_count;
1343
1344 if(wct == 14)
1345 pSMB->ByteCount = cpu_to_le16(byte_count);
1346 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
1347 struct smb_com_writex_req * pSMBW =
1348 (struct smb_com_writex_req *)pSMB;
1349 pSMBW->ByteCount = cpu_to_le16(byte_count);
1350 }
1351
1352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1353 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1354 cifs_stats_inc(&tcon->num_writes);
1355 if (rc) {
1356 cFYI(1, ("Send error in write = %d", rc));
1357 *nbytes = 0;
1358 } else {
1359 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1360 *nbytes = (*nbytes) << 16;
1361 *nbytes += le16_to_cpu(pSMBr->Count);
1362 }
1363
1364 cifs_buf_release(pSMB);
1365
1366 /* Note: On -EAGAIN error only caller can retry on handle based calls
1367 since file handle passed in no longer valid */
1368
1369 return rc;
1370 }
1371
1372 int
1373 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1374 const int netfid, const unsigned int count,
1375 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1376 int n_vec, const int long_op)
1377 {
1378 int rc = -EACCES;
1379 WRITE_REQ *pSMB = NULL;
1380 int wct;
1381 int smb_hdr_len;
1382 int resp_buf_type = 0;
1383
1384 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1385
1386 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1387 wct = 14;
1388 else
1389 wct = 12;
1390 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1391 if (rc)
1392 return rc;
1393 /* tcon and ses pointer are checked in smb_init */
1394 if (tcon->ses->server == NULL)
1395 return -ECONNABORTED;
1396
1397 pSMB->AndXCommand = 0xFF; /* none */
1398 pSMB->Fid = netfid;
1399 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1400 if(wct == 14)
1401 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1402 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1403 return -EIO;
1404 pSMB->Reserved = 0xFFFFFFFF;
1405 pSMB->WriteMode = 0;
1406 pSMB->Remaining = 0;
1407
1408 pSMB->DataOffset =
1409 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1410
1411 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1412 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1413 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1414 if(wct == 14)
1415 pSMB->hdr.smb_buf_length += count+1;
1416 else /* wct == 12 */
1417 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1418 if(wct == 14)
1419 pSMB->ByteCount = cpu_to_le16(count + 1);
1420 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1421 struct smb_com_writex_req * pSMBW =
1422 (struct smb_com_writex_req *)pSMB;
1423 pSMBW->ByteCount = cpu_to_le16(count + 5);
1424 }
1425 iov[0].iov_base = pSMB;
1426 if(wct == 14)
1427 iov[0].iov_len = smb_hdr_len + 4;
1428 else /* wct == 12 pad bigger by four bytes */
1429 iov[0].iov_len = smb_hdr_len + 8;
1430
1431
1432 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1433 long_op);
1434 cifs_stats_inc(&tcon->num_writes);
1435 if (rc) {
1436 cFYI(1, ("Send error Write2 = %d", rc));
1437 *nbytes = 0;
1438 } else if(resp_buf_type == 0) {
1439 /* presumably this can not happen, but best to be safe */
1440 rc = -EIO;
1441 *nbytes = 0;
1442 } else {
1443 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1444 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1445 *nbytes = (*nbytes) << 16;
1446 *nbytes += le16_to_cpu(pSMBr->Count);
1447 }
1448
1449 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1450 if(resp_buf_type == CIFS_SMALL_BUFFER)
1451 cifs_small_buf_release(iov[0].iov_base);
1452 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1453 cifs_buf_release(iov[0].iov_base);
1454
1455 /* Note: On -EAGAIN error only caller can retry on handle based calls
1456 since file handle passed in no longer valid */
1457
1458 return rc;
1459 }
1460
1461
1462 int
1463 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1464 const __u16 smb_file_id, const __u64 len,
1465 const __u64 offset, const __u32 numUnlock,
1466 const __u32 numLock, const __u8 lockType, const int waitFlag)
1467 {
1468 int rc = 0;
1469 LOCK_REQ *pSMB = NULL;
1470 LOCK_RSP *pSMBr = NULL;
1471 int bytes_returned;
1472 int timeout = 0;
1473 __u16 count;
1474
1475 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1476 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1477
1478 if (rc)
1479 return rc;
1480
1481 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1482
1483 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1484 timeout = -1; /* no response expected */
1485 pSMB->Timeout = 0;
1486 } else if (waitFlag == TRUE) {
1487 timeout = 3; /* blocking operation, no timeout */
1488 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1489 } else {
1490 pSMB->Timeout = 0;
1491 }
1492
1493 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1494 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1495 pSMB->LockType = lockType;
1496 pSMB->AndXCommand = 0xFF; /* none */
1497 pSMB->Fid = smb_file_id; /* netfid stays le */
1498
1499 if((numLock != 0) || (numUnlock != 0)) {
1500 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1501 /* BB where to store pid high? */
1502 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1503 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1504 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1505 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1506 count = sizeof(LOCKING_ANDX_RANGE);
1507 } else {
1508 /* oplock break */
1509 count = 0;
1510 }
1511 pSMB->hdr.smb_buf_length += count;
1512 pSMB->ByteCount = cpu_to_le16(count);
1513
1514 if (waitFlag) {
1515 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1516 (struct smb_hdr *) pSMBr, &bytes_returned);
1517 } else {
1518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1519 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1520 }
1521 cifs_stats_inc(&tcon->num_locks);
1522 if (rc) {
1523 cFYI(1, ("Send error in Lock = %d", rc));
1524 }
1525 cifs_small_buf_release(pSMB);
1526
1527 /* Note: On -EAGAIN error only caller can retry on handle based calls
1528 since file handle passed in no longer valid */
1529 return rc;
1530 }
1531
1532 int
1533 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1534 const __u16 smb_file_id, const int get_flag, const __u64 len,
1535 struct file_lock *pLockData, const __u16 lock_type,
1536 const int waitFlag)
1537 {
1538 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1539 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1540 char *data_offset;
1541 struct cifs_posix_lock *parm_data;
1542 int rc = 0;
1543 int timeout = 0;
1544 int bytes_returned = 0;
1545 __u16 params, param_offset, offset, byte_count, count;
1546
1547 cFYI(1, ("Posix Lock"));
1548
1549 if(pLockData == NULL)
1550 return EINVAL;
1551
1552 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1553
1554 if (rc)
1555 return rc;
1556
1557 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1558
1559 params = 6;
1560 pSMB->MaxSetupCount = 0;
1561 pSMB->Reserved = 0;
1562 pSMB->Flags = 0;
1563 pSMB->Reserved2 = 0;
1564 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1565 offset = param_offset + params;
1566
1567 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1568
1569 count = sizeof(struct cifs_posix_lock);
1570 pSMB->MaxParameterCount = cpu_to_le16(2);
1571 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1572 pSMB->SetupCount = 1;
1573 pSMB->Reserved3 = 0;
1574 if(get_flag)
1575 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1576 else
1577 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1578 byte_count = 3 /* pad */ + params + count;
1579 pSMB->DataCount = cpu_to_le16(count);
1580 pSMB->ParameterCount = cpu_to_le16(params);
1581 pSMB->TotalDataCount = pSMB->DataCount;
1582 pSMB->TotalParameterCount = pSMB->ParameterCount;
1583 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1584 parm_data = (struct cifs_posix_lock *)
1585 (((char *) &pSMB->hdr.Protocol) + offset);
1586
1587 parm_data->lock_type = cpu_to_le16(lock_type);
1588 if(waitFlag) {
1589 timeout = 3; /* blocking operation, no timeout */
1590 parm_data->lock_flags = cpu_to_le16(1);
1591 pSMB->Timeout = cpu_to_le32(-1);
1592 } else
1593 pSMB->Timeout = 0;
1594
1595 parm_data->pid = cpu_to_le32(current->tgid);
1596 parm_data->start = cpu_to_le64(pLockData->fl_start);
1597 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1598
1599 pSMB->DataOffset = cpu_to_le16(offset);
1600 pSMB->Fid = smb_file_id;
1601 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1602 pSMB->Reserved4 = 0;
1603 pSMB->hdr.smb_buf_length += byte_count;
1604 pSMB->ByteCount = cpu_to_le16(byte_count);
1605 if (waitFlag) {
1606 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1607 (struct smb_hdr *) pSMBr, &bytes_returned);
1608 } else {
1609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1610 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1611 }
1612
1613 if (rc) {
1614 cFYI(1, ("Send error in Posix Lock = %d", rc));
1615 } else if (get_flag) {
1616 /* lock structure can be returned on get */
1617 __u16 data_offset;
1618 __u16 data_count;
1619 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1620
1621 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1622 rc = -EIO; /* bad smb */
1623 goto plk_err_exit;
1624 }
1625 if(pLockData == NULL) {
1626 rc = -EINVAL;
1627 goto plk_err_exit;
1628 }
1629 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1630 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1631 if(data_count < sizeof(struct cifs_posix_lock)) {
1632 rc = -EIO;
1633 goto plk_err_exit;
1634 }
1635 parm_data = (struct cifs_posix_lock *)
1636 ((char *)&pSMBr->hdr.Protocol + data_offset);
1637 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1638 pLockData->fl_type = F_UNLCK;
1639 }
1640
1641 plk_err_exit:
1642 if (pSMB)
1643 cifs_small_buf_release(pSMB);
1644
1645 /* Note: On -EAGAIN error only caller can retry on handle based calls
1646 since file handle passed in no longer valid */
1647
1648 return rc;
1649 }
1650
1651
1652 int
1653 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1654 {
1655 int rc = 0;
1656 CLOSE_REQ *pSMB = NULL;
1657 CLOSE_RSP *pSMBr = NULL;
1658 int bytes_returned;
1659 cFYI(1, ("In CIFSSMBClose"));
1660
1661 /* do not retry on dead session on close */
1662 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1663 if(rc == -EAGAIN)
1664 return 0;
1665 if (rc)
1666 return rc;
1667
1668 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1669
1670 pSMB->FileID = (__u16) smb_file_id;
1671 pSMB->LastWriteTime = 0xFFFFFFFF;
1672 pSMB->ByteCount = 0;
1673 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1674 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1675 cifs_stats_inc(&tcon->num_closes);
1676 if (rc) {
1677 if(rc!=-EINTR) {
1678 /* EINTR is expected when user ctl-c to kill app */
1679 cERROR(1, ("Send error in Close = %d", rc));
1680 }
1681 }
1682
1683 cifs_small_buf_release(pSMB);
1684
1685 /* Since session is dead, file will be closed on server already */
1686 if(rc == -EAGAIN)
1687 rc = 0;
1688
1689 return rc;
1690 }
1691
1692 int
1693 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1694 const char *fromName, const char *toName,
1695 const struct nls_table *nls_codepage, int remap)
1696 {
1697 int rc = 0;
1698 RENAME_REQ *pSMB = NULL;
1699 RENAME_RSP *pSMBr = NULL;
1700 int bytes_returned;
1701 int name_len, name_len2;
1702 __u16 count;
1703
1704 cFYI(1, ("In CIFSSMBRename"));
1705 renameRetry:
1706 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1707 (void **) &pSMBr);
1708 if (rc)
1709 return rc;
1710
1711 pSMB->BufferFormat = 0x04;
1712 pSMB->SearchAttributes =
1713 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1714 ATTR_DIRECTORY);
1715
1716 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1717 name_len =
1718 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1719 PATH_MAX, nls_codepage, remap);
1720 name_len++; /* trailing null */
1721 name_len *= 2;
1722 pSMB->OldFileName[name_len] = 0x04; /* pad */
1723 /* protocol requires ASCII signature byte on Unicode string */
1724 pSMB->OldFileName[name_len + 1] = 0x00;
1725 name_len2 =
1726 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1727 toName, PATH_MAX, nls_codepage, remap);
1728 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1729 name_len2 *= 2; /* convert to bytes */
1730 } else { /* BB improve the check for buffer overruns BB */
1731 name_len = strnlen(fromName, PATH_MAX);
1732 name_len++; /* trailing null */
1733 strncpy(pSMB->OldFileName, fromName, name_len);
1734 name_len2 = strnlen(toName, PATH_MAX);
1735 name_len2++; /* trailing null */
1736 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1737 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1738 name_len2++; /* trailing null */
1739 name_len2++; /* signature byte */
1740 }
1741
1742 count = 1 /* 1st signature byte */ + name_len + name_len2;
1743 pSMB->hdr.smb_buf_length += count;
1744 pSMB->ByteCount = cpu_to_le16(count);
1745
1746 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1747 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1748 cifs_stats_inc(&tcon->num_renames);
1749 if (rc) {
1750 cFYI(1, ("Send error in rename = %d", rc));
1751 }
1752
1753 cifs_buf_release(pSMB);
1754
1755 if (rc == -EAGAIN)
1756 goto renameRetry;
1757
1758 return rc;
1759 }
1760
1761 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1762 int netfid, char * target_name,
1763 const struct nls_table * nls_codepage, int remap)
1764 {
1765 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1766 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1767 struct set_file_rename * rename_info;
1768 char *data_offset;
1769 char dummy_string[30];
1770 int rc = 0;
1771 int bytes_returned = 0;
1772 int len_of_str;
1773 __u16 params, param_offset, offset, count, byte_count;
1774
1775 cFYI(1, ("Rename to File by handle"));
1776 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1777 (void **) &pSMBr);
1778 if (rc)
1779 return rc;
1780
1781 params = 6;
1782 pSMB->MaxSetupCount = 0;
1783 pSMB->Reserved = 0;
1784 pSMB->Flags = 0;
1785 pSMB->Timeout = 0;
1786 pSMB->Reserved2 = 0;
1787 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1788 offset = param_offset + params;
1789
1790 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1791 rename_info = (struct set_file_rename *) data_offset;
1792 pSMB->MaxParameterCount = cpu_to_le16(2);
1793 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1794 pSMB->SetupCount = 1;
1795 pSMB->Reserved3 = 0;
1796 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1797 byte_count = 3 /* pad */ + params;
1798 pSMB->ParameterCount = cpu_to_le16(params);
1799 pSMB->TotalParameterCount = pSMB->ParameterCount;
1800 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1801 pSMB->DataOffset = cpu_to_le16(offset);
1802 /* construct random name ".cifs_tmp<inodenum><mid>" */
1803 rename_info->overwrite = cpu_to_le32(1);
1804 rename_info->root_fid = 0;
1805 /* unicode only call */
1806 if(target_name == NULL) {
1807 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1808 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1809 dummy_string, 24, nls_codepage, remap);
1810 } else {
1811 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1812 target_name, PATH_MAX, nls_codepage, remap);
1813 }
1814 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1815 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1816 byte_count += count;
1817 pSMB->DataCount = cpu_to_le16(count);
1818 pSMB->TotalDataCount = pSMB->DataCount;
1819 pSMB->Fid = netfid;
1820 pSMB->InformationLevel =
1821 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1822 pSMB->Reserved4 = 0;
1823 pSMB->hdr.smb_buf_length += byte_count;
1824 pSMB->ByteCount = cpu_to_le16(byte_count);
1825 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1826 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1827 cifs_stats_inc(&pTcon->num_t2renames);
1828 if (rc) {
1829 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1830 }
1831
1832 cifs_buf_release(pSMB);
1833
1834 /* Note: On -EAGAIN error only caller can retry on handle based calls
1835 since file handle passed in no longer valid */
1836
1837 return rc;
1838 }
1839
1840 int
1841 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1842 const __u16 target_tid, const char *toName, const int flags,
1843 const struct nls_table *nls_codepage, int remap)
1844 {
1845 int rc = 0;
1846 COPY_REQ *pSMB = NULL;
1847 COPY_RSP *pSMBr = NULL;
1848 int bytes_returned;
1849 int name_len, name_len2;
1850 __u16 count;
1851
1852 cFYI(1, ("In CIFSSMBCopy"));
1853 copyRetry:
1854 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1855 (void **) &pSMBr);
1856 if (rc)
1857 return rc;
1858
1859 pSMB->BufferFormat = 0x04;
1860 pSMB->Tid2 = target_tid;
1861
1862 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1863
1864 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1865 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1866 fromName, PATH_MAX, nls_codepage,
1867 remap);
1868 name_len++; /* trailing null */
1869 name_len *= 2;
1870 pSMB->OldFileName[name_len] = 0x04; /* pad */
1871 /* protocol requires ASCII signature byte on Unicode string */
1872 pSMB->OldFileName[name_len + 1] = 0x00;
1873 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1874 toName, PATH_MAX, nls_codepage, remap);
1875 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1876 name_len2 *= 2; /* convert to bytes */
1877 } else { /* BB improve the check for buffer overruns BB */
1878 name_len = strnlen(fromName, PATH_MAX);
1879 name_len++; /* trailing null */
1880 strncpy(pSMB->OldFileName, fromName, name_len);
1881 name_len2 = strnlen(toName, PATH_MAX);
1882 name_len2++; /* trailing null */
1883 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1884 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1885 name_len2++; /* trailing null */
1886 name_len2++; /* signature byte */
1887 }
1888
1889 count = 1 /* 1st signature byte */ + name_len + name_len2;
1890 pSMB->hdr.smb_buf_length += count;
1891 pSMB->ByteCount = cpu_to_le16(count);
1892
1893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1895 if (rc) {
1896 cFYI(1, ("Send error in copy = %d with %d files copied",
1897 rc, le16_to_cpu(pSMBr->CopyCount)));
1898 }
1899 if (pSMB)
1900 cifs_buf_release(pSMB);
1901
1902 if (rc == -EAGAIN)
1903 goto copyRetry;
1904
1905 return rc;
1906 }
1907
1908 int
1909 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1910 const char *fromName, const char *toName,
1911 const struct nls_table *nls_codepage)
1912 {
1913 TRANSACTION2_SPI_REQ *pSMB = NULL;
1914 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1915 char *data_offset;
1916 int name_len;
1917 int name_len_target;
1918 int rc = 0;
1919 int bytes_returned = 0;
1920 __u16 params, param_offset, offset, byte_count;
1921
1922 cFYI(1, ("In Symlink Unix style"));
1923 createSymLinkRetry:
1924 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1925 (void **) &pSMBr);
1926 if (rc)
1927 return rc;
1928
1929 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1930 name_len =
1931 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1932 /* find define for this maxpathcomponent */
1933 , nls_codepage);
1934 name_len++; /* trailing null */
1935 name_len *= 2;
1936
1937 } else { /* BB improve the check for buffer overruns BB */
1938 name_len = strnlen(fromName, PATH_MAX);
1939 name_len++; /* trailing null */
1940 strncpy(pSMB->FileName, fromName, name_len);
1941 }
1942 params = 6 + name_len;
1943 pSMB->MaxSetupCount = 0;
1944 pSMB->Reserved = 0;
1945 pSMB->Flags = 0;
1946 pSMB->Timeout = 0;
1947 pSMB->Reserved2 = 0;
1948 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1949 InformationLevel) - 4;
1950 offset = param_offset + params;
1951
1952 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1954 name_len_target =
1955 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1956 /* find define for this maxpathcomponent */
1957 , nls_codepage);
1958 name_len_target++; /* trailing null */
1959 name_len_target *= 2;
1960 } else { /* BB improve the check for buffer overruns BB */
1961 name_len_target = strnlen(toName, PATH_MAX);
1962 name_len_target++; /* trailing null */
1963 strncpy(data_offset, toName, name_len_target);
1964 }
1965
1966 pSMB->MaxParameterCount = cpu_to_le16(2);
1967 /* BB find exact max on data count below from sess */
1968 pSMB->MaxDataCount = cpu_to_le16(1000);
1969 pSMB->SetupCount = 1;
1970 pSMB->Reserved3 = 0;
1971 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1972 byte_count = 3 /* pad */ + params + name_len_target;
1973 pSMB->DataCount = cpu_to_le16(name_len_target);
1974 pSMB->ParameterCount = cpu_to_le16(params);
1975 pSMB->TotalDataCount = pSMB->DataCount;
1976 pSMB->TotalParameterCount = pSMB->ParameterCount;
1977 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1978 pSMB->DataOffset = cpu_to_le16(offset);
1979 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1980 pSMB->Reserved4 = 0;
1981 pSMB->hdr.smb_buf_length += byte_count;
1982 pSMB->ByteCount = cpu_to_le16(byte_count);
1983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1985 cifs_stats_inc(&tcon->num_symlinks);
1986 if (rc) {
1987 cFYI(1,
1988 ("Send error in SetPathInfo (create symlink) = %d",
1989 rc));
1990 }
1991
1992 if (pSMB)
1993 cifs_buf_release(pSMB);
1994
1995 if (rc == -EAGAIN)
1996 goto createSymLinkRetry;
1997
1998 return rc;
1999 }
2000
2001 int
2002 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2003 const char *fromName, const char *toName,
2004 const struct nls_table *nls_codepage, int remap)
2005 {
2006 TRANSACTION2_SPI_REQ *pSMB = NULL;
2007 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2008 char *data_offset;
2009 int name_len;
2010 int name_len_target;
2011 int rc = 0;
2012 int bytes_returned = 0;
2013 __u16 params, param_offset, offset, byte_count;
2014
2015 cFYI(1, ("In Create Hard link Unix style"));
2016 createHardLinkRetry:
2017 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2018 (void **) &pSMBr);
2019 if (rc)
2020 return rc;
2021
2022 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2023 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2024 PATH_MAX, nls_codepage, remap);
2025 name_len++; /* trailing null */
2026 name_len *= 2;
2027
2028 } else { /* BB improve the check for buffer overruns BB */
2029 name_len = strnlen(toName, PATH_MAX);
2030 name_len++; /* trailing null */
2031 strncpy(pSMB->FileName, toName, name_len);
2032 }
2033 params = 6 + name_len;
2034 pSMB->MaxSetupCount = 0;
2035 pSMB->Reserved = 0;
2036 pSMB->Flags = 0;
2037 pSMB->Timeout = 0;
2038 pSMB->Reserved2 = 0;
2039 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2040 InformationLevel) - 4;
2041 offset = param_offset + params;
2042
2043 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2045 name_len_target =
2046 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2047 nls_codepage, remap);
2048 name_len_target++; /* trailing null */
2049 name_len_target *= 2;
2050 } else { /* BB improve the check for buffer overruns BB */
2051 name_len_target = strnlen(fromName, PATH_MAX);
2052 name_len_target++; /* trailing null */
2053 strncpy(data_offset, fromName, name_len_target);
2054 }
2055
2056 pSMB->MaxParameterCount = cpu_to_le16(2);
2057 /* BB find exact max on data count below from sess*/
2058 pSMB->MaxDataCount = cpu_to_le16(1000);
2059 pSMB->SetupCount = 1;
2060 pSMB->Reserved3 = 0;
2061 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2062 byte_count = 3 /* pad */ + params + name_len_target;
2063 pSMB->ParameterCount = cpu_to_le16(params);
2064 pSMB->TotalParameterCount = pSMB->ParameterCount;
2065 pSMB->DataCount = cpu_to_le16(name_len_target);
2066 pSMB->TotalDataCount = pSMB->DataCount;
2067 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2068 pSMB->DataOffset = cpu_to_le16(offset);
2069 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2070 pSMB->Reserved4 = 0;
2071 pSMB->hdr.smb_buf_length += byte_count;
2072 pSMB->ByteCount = cpu_to_le16(byte_count);
2073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2075 cifs_stats_inc(&tcon->num_hardlinks);
2076 if (rc) {
2077 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2078 }
2079
2080 cifs_buf_release(pSMB);
2081 if (rc == -EAGAIN)
2082 goto createHardLinkRetry;
2083
2084 return rc;
2085 }
2086
2087 int
2088 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2089 const char *fromName, const char *toName,
2090 const struct nls_table *nls_codepage, int remap)
2091 {
2092 int rc = 0;
2093 NT_RENAME_REQ *pSMB = NULL;
2094 RENAME_RSP *pSMBr = NULL;
2095 int bytes_returned;
2096 int name_len, name_len2;
2097 __u16 count;
2098
2099 cFYI(1, ("In CIFSCreateHardLink"));
2100 winCreateHardLinkRetry:
2101
2102 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2103 (void **) &pSMBr);
2104 if (rc)
2105 return rc;
2106
2107 pSMB->SearchAttributes =
2108 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2109 ATTR_DIRECTORY);
2110 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2111 pSMB->ClusterCount = 0;
2112
2113 pSMB->BufferFormat = 0x04;
2114
2115 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2116 name_len =
2117 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2118 PATH_MAX, nls_codepage, remap);
2119 name_len++; /* trailing null */
2120 name_len *= 2;
2121 pSMB->OldFileName[name_len] = 0; /* pad */
2122 pSMB->OldFileName[name_len + 1] = 0x04;
2123 name_len2 =
2124 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2125 toName, PATH_MAX, nls_codepage, remap);
2126 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2127 name_len2 *= 2; /* convert to bytes */
2128 } else { /* BB improve the check for buffer overruns BB */
2129 name_len = strnlen(fromName, PATH_MAX);
2130 name_len++; /* trailing null */
2131 strncpy(pSMB->OldFileName, fromName, name_len);
2132 name_len2 = strnlen(toName, PATH_MAX);
2133 name_len2++; /* trailing null */
2134 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2135 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2136 name_len2++; /* trailing null */
2137 name_len2++; /* signature byte */
2138 }
2139
2140 count = 1 /* string type byte */ + name_len + name_len2;
2141 pSMB->hdr.smb_buf_length += count;
2142 pSMB->ByteCount = cpu_to_le16(count);
2143
2144 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2145 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2146 cifs_stats_inc(&tcon->num_hardlinks);
2147 if (rc) {
2148 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2149 }
2150 cifs_buf_release(pSMB);
2151 if (rc == -EAGAIN)
2152 goto winCreateHardLinkRetry;
2153
2154 return rc;
2155 }
2156
2157 int
2158 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2159 const unsigned char *searchName,
2160 char *symlinkinfo, const int buflen,
2161 const struct nls_table *nls_codepage)
2162 {
2163 /* SMB_QUERY_FILE_UNIX_LINK */
2164 TRANSACTION2_QPI_REQ *pSMB = NULL;
2165 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2166 int rc = 0;
2167 int bytes_returned;
2168 int name_len;
2169 __u16 params, byte_count;
2170
2171 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2172
2173 querySymLinkRetry:
2174 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2175 (void **) &pSMBr);
2176 if (rc)
2177 return rc;
2178
2179 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2180 name_len =
2181 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2182 /* find define for this maxpathcomponent */
2183 , nls_codepage);
2184 name_len++; /* trailing null */
2185 name_len *= 2;
2186 } else { /* BB improve the check for buffer overruns BB */
2187 name_len = strnlen(searchName, PATH_MAX);
2188 name_len++; /* trailing null */
2189 strncpy(pSMB->FileName, searchName, name_len);
2190 }
2191
2192 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2193 pSMB->TotalDataCount = 0;
2194 pSMB->MaxParameterCount = cpu_to_le16(2);
2195 /* BB find exact max data count below from sess structure BB */
2196 pSMB->MaxDataCount = cpu_to_le16(4000);
2197 pSMB->MaxSetupCount = 0;
2198 pSMB->Reserved = 0;
2199 pSMB->Flags = 0;
2200 pSMB->Timeout = 0;
2201 pSMB->Reserved2 = 0;
2202 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2203 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2204 pSMB->DataCount = 0;
2205 pSMB->DataOffset = 0;
2206 pSMB->SetupCount = 1;
2207 pSMB->Reserved3 = 0;
2208 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2209 byte_count = params + 1 /* pad */ ;
2210 pSMB->TotalParameterCount = cpu_to_le16(params);
2211 pSMB->ParameterCount = pSMB->TotalParameterCount;
2212 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2213 pSMB->Reserved4 = 0;
2214 pSMB->hdr.smb_buf_length += byte_count;
2215 pSMB->ByteCount = cpu_to_le16(byte_count);
2216
2217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2219 if (rc) {
2220 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2221 } else {
2222 /* decode response */
2223
2224 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2225 if (rc || (pSMBr->ByteCount < 2))
2226 /* BB also check enough total bytes returned */
2227 rc = -EIO; /* bad smb */
2228 else {
2229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2230 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2231
2232 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2233 name_len = UniStrnlen((wchar_t *) ((char *)
2234 &pSMBr->hdr.Protocol +data_offset),
2235 min_t(const int, buflen,count) / 2);
2236 /* BB FIXME investigate remapping reserved chars here */
2237 cifs_strfromUCS_le(symlinkinfo,
2238 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
2239 data_offset),
2240 name_len, nls_codepage);
2241 } else {
2242 strncpy(symlinkinfo,
2243 (char *) &pSMBr->hdr.Protocol +
2244 data_offset,
2245 min_t(const int, buflen, count));
2246 }
2247 symlinkinfo[buflen] = 0;
2248 /* just in case so calling code does not go off the end of buffer */
2249 }
2250 }
2251 cifs_buf_release(pSMB);
2252 if (rc == -EAGAIN)
2253 goto querySymLinkRetry;
2254 return rc;
2255 }
2256
2257 /* Initialize NT TRANSACT SMB into small smb request buffer.
2258 This assumes that all NT TRANSACTS that we init here have
2259 total parm and data under about 400 bytes (to fit in small cifs
2260 buffer size), which is the case so far, it easily fits. NB:
2261 Setup words themselves and ByteCount
2262 MaxSetupCount (size of returned setup area) and
2263 MaxParameterCount (returned parms size) must be set by caller */
2264 static int
2265 smb_init_ntransact(const __u16 sub_command, const int setup_count,
2266 const int parm_len, struct cifsTconInfo *tcon,
2267 void ** ret_buf)
2268 {
2269 int rc;
2270 __u32 temp_offset;
2271 struct smb_com_ntransact_req * pSMB;
2272
2273 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2274 (void **)&pSMB);
2275 if (rc)
2276 return rc;
2277 *ret_buf = (void *)pSMB;
2278 pSMB->Reserved = 0;
2279 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2280 pSMB->TotalDataCount = 0;
2281 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2282 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2283 pSMB->ParameterCount = pSMB->TotalParameterCount;
2284 pSMB->DataCount = pSMB->TotalDataCount;
2285 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2286 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2287 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2288 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2289 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2290 pSMB->SubCommand = cpu_to_le16(sub_command);
2291 return 0;
2292 }
2293
2294 static int
2295 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2296 int * pdatalen, int * pparmlen)
2297 {
2298 char * end_of_smb;
2299 __u32 data_count, data_offset, parm_count, parm_offset;
2300 struct smb_com_ntransact_rsp * pSMBr;
2301
2302 if(buf == NULL)
2303 return -EINVAL;
2304
2305 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2306
2307 /* ByteCount was converted from little endian in SendReceive */
2308 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2309 (char *)&pSMBr->ByteCount;
2310
2311
2312 data_offset = le32_to_cpu(pSMBr->DataOffset);
2313 data_count = le32_to_cpu(pSMBr->DataCount);
2314 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2315 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2316
2317 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2318 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2319
2320 /* should we also check that parm and data areas do not overlap? */
2321 if(*ppparm > end_of_smb) {
2322 cFYI(1,("parms start after end of smb"));
2323 return -EINVAL;
2324 } else if(parm_count + *ppparm > end_of_smb) {
2325 cFYI(1,("parm end after end of smb"));
2326 return -EINVAL;
2327 } else if(*ppdata > end_of_smb) {
2328 cFYI(1,("data starts after end of smb"));
2329 return -EINVAL;
2330 } else if(data_count + *ppdata > end_of_smb) {
2331 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2332 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2333 return -EINVAL;
2334 } else if(parm_count + data_count > pSMBr->ByteCount) {
2335 cFYI(1,("parm count and data count larger than SMB"));
2336 return -EINVAL;
2337 }
2338 return 0;
2339 }
2340
2341 int
2342 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2343 const unsigned char *searchName,
2344 char *symlinkinfo, const int buflen,__u16 fid,
2345 const struct nls_table *nls_codepage)
2346 {
2347 int rc = 0;
2348 int bytes_returned;
2349 int name_len;
2350 struct smb_com_transaction_ioctl_req * pSMB;
2351 struct smb_com_transaction_ioctl_rsp * pSMBr;
2352
2353 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2354 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2355 (void **) &pSMBr);
2356 if (rc)
2357 return rc;
2358
2359 pSMB->TotalParameterCount = 0 ;
2360 pSMB->TotalDataCount = 0;
2361 pSMB->MaxParameterCount = cpu_to_le32(2);
2362 /* BB find exact data count max from sess structure BB */
2363 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2364 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2365 pSMB->MaxSetupCount = 4;
2366 pSMB->Reserved = 0;
2367 pSMB->ParameterOffset = 0;
2368 pSMB->DataCount = 0;
2369 pSMB->DataOffset = 0;
2370 pSMB->SetupCount = 4;
2371 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2372 pSMB->ParameterCount = pSMB->TotalParameterCount;
2373 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2374 pSMB->IsFsctl = 1; /* FSCTL */
2375 pSMB->IsRootFlag = 0;
2376 pSMB->Fid = fid; /* file handle always le */
2377 pSMB->ByteCount = 0;
2378
2379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2380 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2381 if (rc) {
2382 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2383 } else { /* decode response */
2384 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2385 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2386 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2387 /* BB also check enough total bytes returned */
2388 rc = -EIO; /* bad smb */
2389 else {
2390 if(data_count && (data_count < 2048)) {
2391 char * end_of_smb = 2 /* sizeof byte count */ +
2392 pSMBr->ByteCount +
2393 (char *)&pSMBr->ByteCount;
2394
2395 struct reparse_data * reparse_buf = (struct reparse_data *)
2396 ((char *)&pSMBr->hdr.Protocol + data_offset);
2397 if((char*)reparse_buf >= end_of_smb) {
2398 rc = -EIO;
2399 goto qreparse_out;
2400 }
2401 if((reparse_buf->LinkNamesBuf +
2402 reparse_buf->TargetNameOffset +
2403 reparse_buf->TargetNameLen) >
2404 end_of_smb) {
2405 cFYI(1,("reparse buf extended beyond SMB"));
2406 rc = -EIO;
2407 goto qreparse_out;
2408 }
2409
2410 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2411 name_len = UniStrnlen((wchar_t *)
2412 (reparse_buf->LinkNamesBuf +
2413 reparse_buf->TargetNameOffset),
2414 min(buflen/2, reparse_buf->TargetNameLen / 2));
2415 cifs_strfromUCS_le(symlinkinfo,
2416 (__le16 *) (reparse_buf->LinkNamesBuf +
2417 reparse_buf->TargetNameOffset),
2418 name_len, nls_codepage);
2419 } else { /* ASCII names */
2420 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2421 reparse_buf->TargetNameOffset,
2422 min_t(const int, buflen, reparse_buf->TargetNameLen));
2423 }
2424 } else {
2425 rc = -EIO;
2426 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2427 }
2428 symlinkinfo[buflen] = 0; /* just in case so the caller
2429 does not go off the end of the buffer */
2430 cFYI(1,("readlink result - %s",symlinkinfo));
2431 }
2432 }
2433 qreparse_out:
2434 cifs_buf_release(pSMB);
2435
2436 /* Note: On -EAGAIN error only caller can retry on handle based calls
2437 since file handle passed in no longer valid */
2438
2439 return rc;
2440 }
2441
2442 #ifdef CONFIG_CIFS_POSIX
2443
2444 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2445 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2446 {
2447 /* u8 cifs fields do not need le conversion */
2448 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2449 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2450 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2451 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2452
2453 return;
2454 }
2455
2456 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2457 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2458 const int acl_type,const int size_of_data_area)
2459 {
2460 int size = 0;
2461 int i;
2462 __u16 count;
2463 struct cifs_posix_ace * pACE;
2464 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2465 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2466
2467 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2468 return -EOPNOTSUPP;
2469
2470 if(acl_type & ACL_TYPE_ACCESS) {
2471 count = le16_to_cpu(cifs_acl->access_entry_count);
2472 pACE = &cifs_acl->ace_array[0];
2473 size = sizeof(struct cifs_posix_acl);
2474 size += sizeof(struct cifs_posix_ace) * count;
2475 /* check if we would go beyond end of SMB */
2476 if(size_of_data_area < size) {
2477 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2478 return -EINVAL;
2479 }
2480 } else if(acl_type & ACL_TYPE_DEFAULT) {
2481 count = le16_to_cpu(cifs_acl->access_entry_count);
2482 size = sizeof(struct cifs_posix_acl);
2483 size += sizeof(struct cifs_posix_ace) * count;
2484 /* skip past access ACEs to get to default ACEs */
2485 pACE = &cifs_acl->ace_array[count];
2486 count = le16_to_cpu(cifs_acl->default_entry_count);
2487 size += sizeof(struct cifs_posix_ace) * count;
2488 /* check if we would go beyond end of SMB */
2489 if(size_of_data_area < size)
2490 return -EINVAL;
2491 } else {
2492 /* illegal type */
2493 return -EINVAL;
2494 }
2495
2496 size = posix_acl_xattr_size(count);
2497 if((buflen == 0) || (local_acl == NULL)) {
2498 /* used to query ACL EA size */
2499 } else if(size > buflen) {
2500 return -ERANGE;
2501 } else /* buffer big enough */ {
2502 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2503 for(i = 0;i < count ;i++) {
2504 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2505 pACE ++;
2506 }
2507 }
2508 return size;
2509 }
2510
2511 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2512 const posix_acl_xattr_entry * local_ace)
2513 {
2514 __u16 rc = 0; /* 0 = ACL converted ok */
2515
2516 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2517 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2518 /* BB is there a better way to handle the large uid? */
2519 if(local_ace->e_id == cpu_to_le32(-1)) {
2520 /* Probably no need to le convert -1 on any arch but can not hurt */
2521 cifs_ace->cifs_uid = cpu_to_le64(-1);
2522 } else
2523 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2524 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2525 return rc;
2526 }
2527
2528 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2529 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2530 const int acl_type)
2531 {
2532 __u16 rc = 0;
2533 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2534 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2535 int count;
2536 int i;
2537
2538 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2539 return 0;
2540
2541 count = posix_acl_xattr_count((size_t)buflen);
2542 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2543 count, buflen, le32_to_cpu(local_acl->a_version)));
2544 if(le32_to_cpu(local_acl->a_version) != 2) {
2545 cFYI(1,("unknown POSIX ACL version %d",
2546 le32_to_cpu(local_acl->a_version)));
2547 return 0;
2548 }
2549 cifs_acl->version = cpu_to_le16(1);
2550 if(acl_type == ACL_TYPE_ACCESS)
2551 cifs_acl->access_entry_count = cpu_to_le16(count);
2552 else if(acl_type == ACL_TYPE_DEFAULT)
2553 cifs_acl->default_entry_count = cpu_to_le16(count);
2554 else {
2555 cFYI(1,("unknown ACL type %d",acl_type));
2556 return 0;
2557 }
2558 for(i=0;i<count;i++) {
2559 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2560 &local_acl->a_entries[i]);
2561 if(rc != 0) {
2562 /* ACE not converted */
2563 break;
2564 }
2565 }
2566 if(rc == 0) {
2567 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2568 rc += sizeof(struct cifs_posix_acl);
2569 /* BB add check to make sure ACL does not overflow SMB */
2570 }
2571 return rc;
2572 }
2573
2574 int
2575 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2576 const unsigned char *searchName,
2577 char *acl_inf, const int buflen, const int acl_type,
2578 const struct nls_table *nls_codepage, int remap)
2579 {
2580 /* SMB_QUERY_POSIX_ACL */
2581 TRANSACTION2_QPI_REQ *pSMB = NULL;
2582 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2583 int rc = 0;
2584 int bytes_returned;
2585 int name_len;
2586 __u16 params, byte_count;
2587
2588 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2589
2590 queryAclRetry:
2591 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2592 (void **) &pSMBr);
2593 if (rc)
2594 return rc;
2595
2596 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2597 name_len =
2598 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2599 PATH_MAX, nls_codepage, remap);
2600 name_len++; /* trailing null */
2601 name_len *= 2;
2602 pSMB->FileName[name_len] = 0;
2603 pSMB->FileName[name_len+1] = 0;
2604 } else { /* BB improve the check for buffer overruns BB */
2605 name_len = strnlen(searchName, PATH_MAX);
2606 name_len++; /* trailing null */
2607 strncpy(pSMB->FileName, searchName, name_len);
2608 }
2609
2610 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2611 pSMB->TotalDataCount = 0;
2612 pSMB->MaxParameterCount = cpu_to_le16(2);
2613 /* BB find exact max data count below from sess structure BB */
2614 pSMB->MaxDataCount = cpu_to_le16(4000);
2615 pSMB->MaxSetupCount = 0;
2616 pSMB->Reserved = 0;
2617 pSMB->Flags = 0;
2618 pSMB->Timeout = 0;
2619 pSMB->Reserved2 = 0;
2620 pSMB->ParameterOffset = cpu_to_le16(
2621 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2622 pSMB->DataCount = 0;
2623 pSMB->DataOffset = 0;
2624 pSMB->SetupCount = 1;
2625 pSMB->Reserved3 = 0;
2626 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2627 byte_count = params + 1 /* pad */ ;
2628 pSMB->TotalParameterCount = cpu_to_le16(params);
2629 pSMB->ParameterCount = pSMB->TotalParameterCount;
2630 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2631 pSMB->Reserved4 = 0;
2632 pSMB->hdr.smb_buf_length += byte_count;
2633 pSMB->ByteCount = cpu_to_le16(byte_count);
2634
2635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2637 cifs_stats_inc(&tcon->num_acl_get);
2638 if (rc) {
2639 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2640 } else {
2641 /* decode response */
2642
2643 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2644 if (rc || (pSMBr->ByteCount < 2))
2645 /* BB also check enough total bytes returned */
2646 rc = -EIO; /* bad smb */
2647 else {
2648 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2649 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2650 rc = cifs_copy_posix_acl(acl_inf,
2651 (char *)&pSMBr->hdr.Protocol+data_offset,
2652 buflen,acl_type,count);
2653 }
2654 }
2655 cifs_buf_release(pSMB);
2656 if (rc == -EAGAIN)
2657 goto queryAclRetry;
2658 return rc;
2659 }
2660
2661 int
2662 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2663 const unsigned char *fileName,
2664 const char *local_acl, const int buflen,
2665 const int acl_type,
2666 const struct nls_table *nls_codepage, int remap)
2667 {
2668 struct smb_com_transaction2_spi_req *pSMB = NULL;
2669 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2670 char *parm_data;
2671 int name_len;
2672 int rc = 0;
2673 int bytes_returned = 0;
2674 __u16 params, byte_count, data_count, param_offset, offset;
2675
2676 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2677 setAclRetry:
2678 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2679 (void **) &pSMBr);
2680 if (rc)
2681 return rc;
2682 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2683 name_len =
2684 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2685 PATH_MAX, nls_codepage, remap);
2686 name_len++; /* trailing null */
2687 name_len *= 2;
2688 } else { /* BB improve the check for buffer overruns BB */
2689 name_len = strnlen(fileName, PATH_MAX);
2690 name_len++; /* trailing null */
2691 strncpy(pSMB->FileName, fileName, name_len);
2692 }
2693 params = 6 + name_len;
2694 pSMB->MaxParameterCount = cpu_to_le16(2);
2695 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2696 pSMB->MaxSetupCount = 0;
2697 pSMB->Reserved = 0;
2698 pSMB->Flags = 0;
2699 pSMB->Timeout = 0;
2700 pSMB->Reserved2 = 0;
2701 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2702 InformationLevel) - 4;
2703 offset = param_offset + params;
2704 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2705 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2706
2707 /* convert to on the wire format for POSIX ACL */
2708 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2709
2710 if(data_count == 0) {
2711 rc = -EOPNOTSUPP;
2712 goto setACLerrorExit;
2713 }
2714 pSMB->DataOffset = cpu_to_le16(offset);
2715 pSMB->SetupCount = 1;
2716 pSMB->Reserved3 = 0;
2717 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2718 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2719 byte_count = 3 /* pad */ + params + data_count;
2720 pSMB->DataCount = cpu_to_le16(data_count);
2721 pSMB->TotalDataCount = pSMB->DataCount;
2722 pSMB->ParameterCount = cpu_to_le16(params);
2723 pSMB->TotalParameterCount = pSMB->ParameterCount;
2724 pSMB->Reserved4 = 0;
2725 pSMB->hdr.smb_buf_length += byte_count;
2726 pSMB->ByteCount = cpu_to_le16(byte_count);
2727 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2728 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2729 if (rc) {
2730 cFYI(1, ("Set POSIX ACL returned %d", rc));
2731 }
2732
2733 setACLerrorExit:
2734 cifs_buf_release(pSMB);
2735 if (rc == -EAGAIN)
2736 goto setAclRetry;
2737 return rc;
2738 }
2739
2740 /* BB fix tabs in this function FIXME BB */
2741 int
2742 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2743 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2744 {
2745 int rc = 0;
2746 struct smb_t2_qfi_req *pSMB = NULL;
2747 struct smb_t2_qfi_rsp *pSMBr = NULL;
2748 int bytes_returned;
2749 __u16 params, byte_count;
2750
2751 cFYI(1,("In GetExtAttr"));
2752 if(tcon == NULL)
2753 return -ENODEV;
2754
2755 GetExtAttrRetry:
2756 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2757 (void **) &pSMBr);
2758 if (rc)
2759 return rc;
2760
2761 params = 2 /* level */ +2 /* fid */;
2762 pSMB->t2.TotalDataCount = 0;
2763 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2764 /* BB find exact max data count below from sess structure BB */
2765 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2766 pSMB->t2.MaxSetupCount = 0;
2767 pSMB->t2.Reserved = 0;
2768 pSMB->t2.Flags = 0;
2769 pSMB->t2.Timeout = 0;
2770 pSMB->t2.Reserved2 = 0;
2771 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2772 Fid) - 4);
2773 pSMB->t2.DataCount = 0;
2774 pSMB->t2.DataOffset = 0;
2775 pSMB->t2.SetupCount = 1;
2776 pSMB->t2.Reserved3 = 0;
2777 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2778 byte_count = params + 1 /* pad */ ;
2779 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2780 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2781 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2782 pSMB->Pad = 0;
2783 pSMB->Fid = netfid;
2784 pSMB->hdr.smb_buf_length += byte_count;
2785 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2786
2787 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2788 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2789 if (rc) {
2790 cFYI(1, ("error %d in GetExtAttr", rc));
2791 } else {
2792 /* decode response */
2793 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2794 if (rc || (pSMBr->ByteCount < 2))
2795 /* BB also check enough total bytes returned */
2796 /* If rc should we check for EOPNOSUPP and
2797 disable the srvino flag? or in caller? */
2798 rc = -EIO; /* bad smb */
2799 else {
2800 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2801 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2802 struct file_chattr_info * pfinfo;
2803 /* BB Do we need a cast or hash here ? */
2804 if(count != 16) {
2805 cFYI(1, ("Illegal size ret in GetExtAttr"));
2806 rc = -EIO;
2807 goto GetExtAttrOut;
2808 }
2809 pfinfo = (struct file_chattr_info *)
2810 (data_offset + (char *) &pSMBr->hdr.Protocol);
2811 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2812 *pMask = le64_to_cpu(pfinfo->mask);
2813 }
2814 }
2815 GetExtAttrOut:
2816 cifs_buf_release(pSMB);
2817 if (rc == -EAGAIN)
2818 goto GetExtAttrRetry;
2819 return rc;
2820 }
2821
2822
2823 #endif /* CONFIG_POSIX */
2824
2825
2826 /* security id for everyone */
2827 const static struct cifs_sid sid_everyone =
2828 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2829 /* group users */
2830 const static struct cifs_sid sid_user =
2831 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2832
2833 /* Convert CIFS ACL to POSIX form */
2834 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2835 {
2836 return 0;
2837 }
2838
2839 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2840 int
2841 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2842 /* BB fix up return info */ char *acl_inf, const int buflen,
2843 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2844 {
2845 int rc = 0;
2846 int buf_type = 0;
2847 QUERY_SEC_DESC_REQ * pSMB;
2848 struct kvec iov[1];
2849
2850 cFYI(1, ("GetCifsACL"));
2851
2852 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2853 8 /* parm len */, tcon, (void **) &pSMB);
2854 if (rc)
2855 return rc;
2856
2857 pSMB->MaxParameterCount = cpu_to_le32(4);
2858 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2859 pSMB->MaxSetupCount = 0;
2860 pSMB->Fid = fid; /* file handle always le */
2861 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2862 CIFS_ACL_DACL);
2863 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2864 pSMB->hdr.smb_buf_length += 11;
2865 iov[0].iov_base = (char *)pSMB;
2866 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2867
2868 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2869 cifs_stats_inc(&tcon->num_acl_get);
2870 if (rc) {
2871 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2872 } else { /* decode response */
2873 struct cifs_sid * psec_desc;
2874 __le32 * parm;
2875 int parm_len;
2876 int data_len;
2877 int acl_len;
2878 struct smb_com_ntransact_rsp * pSMBr;
2879
2880 /* validate_nttransact */
2881 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2882 (char **)&psec_desc,
2883 &parm_len, &data_len);
2884
2885 if(rc)
2886 goto qsec_out;
2887 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2888
2889 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2890
2891 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2892 rc = -EIO; /* bad smb */
2893 goto qsec_out;
2894 }
2895
2896 /* BB check that data area is minimum length and as big as acl_len */
2897
2898 acl_len = le32_to_cpu(*(__le32 *)parm);
2899 /* BB check if(acl_len > bufsize) */
2900
2901 parse_sec_desc(psec_desc, acl_len);
2902 }
2903 qsec_out:
2904 if(buf_type == CIFS_SMALL_BUFFER)
2905 cifs_small_buf_release(iov[0].iov_base);
2906 else if(buf_type == CIFS_LARGE_BUFFER)
2907 cifs_buf_release(iov[0].iov_base);
2908 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2909 return rc;
2910 }
2911
2912 /* Legacy Query Path Information call for lookup to old servers such
2913 as Win9x/WinME */
2914 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2915 const unsigned char *searchName,
2916 FILE_ALL_INFO * pFinfo,
2917 const struct nls_table *nls_codepage, int remap)
2918 {
2919 QUERY_INFORMATION_REQ * pSMB;
2920 QUERY_INFORMATION_RSP * pSMBr;
2921 int rc = 0;
2922 int bytes_returned;
2923 int name_len;
2924
2925 cFYI(1, ("In SMBQPath path %s", searchName));
2926 QInfRetry:
2927 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2928 (void **) &pSMBr);
2929 if (rc)
2930 return rc;
2931
2932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2933 name_len =
2934 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2935 PATH_MAX, nls_codepage, remap);
2936 name_len++; /* trailing null */
2937 name_len *= 2;
2938 } else {
2939 name_len = strnlen(searchName, PATH_MAX);
2940 name_len++; /* trailing null */
2941 strncpy(pSMB->FileName, searchName, name_len);
2942 }
2943 pSMB->BufferFormat = 0x04;
2944 name_len++; /* account for buffer type byte */
2945 pSMB->hdr.smb_buf_length += (__u16) name_len;
2946 pSMB->ByteCount = cpu_to_le16(name_len);
2947
2948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2950 if (rc) {
2951 cFYI(1, ("Send error in QueryInfo = %d", rc));
2952 } else if (pFinfo) { /* decode response */
2953 struct timespec ts;
2954 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2955 /* BB FIXME - add time zone adjustment BB */
2956 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2957 ts.tv_nsec = 0;
2958 ts.tv_sec = time;
2959 /* decode time fields */
2960 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
2961 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2962 pFinfo->LastAccessTime = 0;
2963 pFinfo->AllocationSize =
2964 cpu_to_le64(le32_to_cpu(pSMBr->size));
2965 pFinfo->EndOfFile = pFinfo->AllocationSize;
2966 pFinfo->Attributes =
2967 cpu_to_le32(le16_to_cpu(pSMBr->attr));
2968 } else
2969 rc = -EIO; /* bad buffer passed in */
2970
2971 cifs_buf_release(pSMB);
2972
2973 if (rc == -EAGAIN)
2974 goto QInfRetry;
2975
2976 return rc;
2977 }
2978
2979
2980
2981
2982 int
2983 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2984 const unsigned char *searchName,
2985 FILE_ALL_INFO * pFindData,
2986 int legacy /* old style infolevel */,
2987 const struct nls_table *nls_codepage, int remap)
2988 {
2989 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2990 TRANSACTION2_QPI_REQ *pSMB = NULL;
2991 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2992 int rc = 0;
2993 int bytes_returned;
2994 int name_len;
2995 __u16 params, byte_count;
2996
2997 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2998 QPathInfoRetry:
2999 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3000 (void **) &pSMBr);
3001 if (rc)
3002 return rc;
3003
3004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3005 name_len =
3006 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3007 PATH_MAX, nls_codepage, remap);
3008 name_len++; /* trailing null */
3009 name_len *= 2;
3010 } else { /* BB improve the check for buffer overruns BB */
3011 name_len = strnlen(searchName, PATH_MAX);
3012 name_len++; /* trailing null */
3013 strncpy(pSMB->FileName, searchName, name_len);
3014 }
3015
3016 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3017 pSMB->TotalDataCount = 0;
3018 pSMB->MaxParameterCount = cpu_to_le16(2);
3019 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3020 pSMB->MaxSetupCount = 0;
3021 pSMB->Reserved = 0;
3022 pSMB->Flags = 0;
3023 pSMB->Timeout = 0;
3024 pSMB->Reserved2 = 0;
3025 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3026 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3027 pSMB->DataCount = 0;
3028 pSMB->DataOffset = 0;
3029 pSMB->SetupCount = 1;
3030 pSMB->Reserved3 = 0;
3031 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3032 byte_count = params + 1 /* pad */ ;
3033 pSMB->TotalParameterCount = cpu_to_le16(params);
3034 pSMB->ParameterCount = pSMB->TotalParameterCount;
3035 if(legacy)
3036 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3037 else
3038 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3039 pSMB->Reserved4 = 0;
3040 pSMB->hdr.smb_buf_length += byte_count;
3041 pSMB->ByteCount = cpu_to_le16(byte_count);
3042
3043 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3045 if (rc) {
3046 cFYI(1, ("Send error in QPathInfo = %d", rc));
3047 } else { /* decode response */
3048 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3049
3050 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3051 rc = -EIO;
3052 else if (!legacy && (pSMBr->ByteCount < 40))
3053 rc = -EIO; /* bad smb */
3054 else if(legacy && (pSMBr->ByteCount < 24))
3055 rc = -EIO; /* 24 or 26 expected but we do not read last field */
3056 else if (pFindData){
3057 int size;
3058 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3059 if(legacy) /* we do not read the last field, EAsize, fortunately
3060 since it varies by subdialect and on Set vs. Get, is
3061 two bytes or 4 bytes depending but we don't care here */
3062 size = sizeof(FILE_INFO_STANDARD);
3063 else
3064 size = sizeof(FILE_ALL_INFO);
3065 memcpy((char *) pFindData,
3066 (char *) &pSMBr->hdr.Protocol +
3067 data_offset, size);
3068 } else
3069 rc = -ENOMEM;
3070 }
3071 cifs_buf_release(pSMB);
3072 if (rc == -EAGAIN)
3073 goto QPathInfoRetry;
3074
3075 return rc;
3076 }
3077
3078 int
3079 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3080 const unsigned char *searchName,
3081 FILE_UNIX_BASIC_INFO * pFindData,
3082 const struct nls_table *nls_codepage, int remap)
3083 {
3084 /* SMB_QUERY_FILE_UNIX_BASIC */
3085 TRANSACTION2_QPI_REQ *pSMB = NULL;
3086 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3087 int rc = 0;
3088 int bytes_returned = 0;
3089 int name_len;
3090 __u16 params, byte_count;
3091
3092 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3093 UnixQPathInfoRetry:
3094 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3095 (void **) &pSMBr);
3096 if (rc)
3097 return rc;
3098
3099 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3100 name_len =
3101 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3102 PATH_MAX, nls_codepage, remap);
3103 name_len++; /* trailing null */
3104 name_len *= 2;
3105 } else { /* BB improve the check for buffer overruns BB */
3106 name_len = strnlen(searchName, PATH_MAX);
3107 name_len++; /* trailing null */
3108 strncpy(pSMB->FileName, searchName, name_len);
3109 }
3110
3111 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3112 pSMB->TotalDataCount = 0;
3113 pSMB->MaxParameterCount = cpu_to_le16(2);
3114 /* BB find exact max SMB PDU from sess structure BB */
3115 pSMB->MaxDataCount = cpu_to_le16(4000);
3116 pSMB->MaxSetupCount = 0;
3117 pSMB->Reserved = 0;
3118 pSMB->Flags = 0;
3119 pSMB->Timeout = 0;
3120 pSMB->Reserved2 = 0;
3121 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3122 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3123 pSMB->DataCount = 0;
3124 pSMB->DataOffset = 0;
3125 pSMB->SetupCount = 1;
3126 pSMB->Reserved3 = 0;
3127 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3128 byte_count = params + 1 /* pad */ ;
3129 pSMB->TotalParameterCount = cpu_to_le16(params);
3130 pSMB->ParameterCount = pSMB->TotalParameterCount;
3131 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3132 pSMB->Reserved4 = 0;
3133 pSMB->hdr.smb_buf_length += byte_count;
3134 pSMB->ByteCount = cpu_to_le16(byte_count);
3135
3136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3138 if (rc) {
3139 cFYI(1, ("Send error in QPathInfo = %d", rc));
3140 } else { /* decode response */
3141 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3142
3143 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3144 rc = -EIO; /* bad smb */
3145 } else {
3146 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3147 memcpy((char *) pFindData,
3148 (char *) &pSMBr->hdr.Protocol +
3149 data_offset,
3150 sizeof (FILE_UNIX_BASIC_INFO));
3151 }
3152 }
3153 cifs_buf_release(pSMB);
3154 if (rc == -EAGAIN)
3155 goto UnixQPathInfoRetry;
3156
3157 return rc;
3158 }
3159
3160 #if 0 /* function unused at present */
3161 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3162 const char *searchName, FILE_ALL_INFO * findData,
3163 const struct nls_table *nls_codepage)
3164 {
3165 /* level 257 SMB_ */
3166 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3167 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3168 int rc = 0;
3169 int bytes_returned;
3170 int name_len;
3171 __u16 params, byte_count;
3172
3173 cFYI(1, ("In FindUnique"));
3174 findUniqueRetry:
3175 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3176 (void **) &pSMBr);
3177 if (rc)
3178 return rc;
3179
3180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3181 name_len =
3182 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
3183 /* find define for this maxpathcomponent */
3184 , nls_codepage);
3185 name_len++; /* trailing null */
3186 name_len *= 2;
3187 } else { /* BB improve the check for buffer overruns BB */
3188 name_len = strnlen(searchName, PATH_MAX);
3189 name_len++; /* trailing null */
3190 strncpy(pSMB->FileName, searchName, name_len);
3191 }
3192
3193 params = 12 + name_len /* includes null */ ;
3194 pSMB->TotalDataCount = 0; /* no EAs */
3195 pSMB->MaxParameterCount = cpu_to_le16(2);
3196 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3197 pSMB->MaxSetupCount = 0;
3198 pSMB->Reserved = 0;
3199 pSMB->Flags = 0;
3200 pSMB->Timeout = 0;
3201 pSMB->Reserved2 = 0;
3202 pSMB->ParameterOffset = cpu_to_le16(
3203 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3204 pSMB->DataCount = 0;
3205 pSMB->DataOffset = 0;
3206 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3207 pSMB->Reserved3 = 0;
3208 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3209 byte_count = params + 1 /* pad */ ;
3210 pSMB->TotalParameterCount = cpu_to_le16(params);
3211 pSMB->ParameterCount = pSMB->TotalParameterCount;
3212 pSMB->SearchAttributes =
3213 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3214 ATTR_DIRECTORY);
3215 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3216 pSMB->SearchFlags = cpu_to_le16(1);
3217 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3218 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3219 pSMB->hdr.smb_buf_length += byte_count;
3220 pSMB->ByteCount = cpu_to_le16(byte_count);
3221
3222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3224
3225 if (rc) {
3226 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3227 } else { /* decode response */
3228 cifs_stats_inc(&tcon->num_ffirst);
3229 /* BB fill in */
3230 }
3231
3232 cifs_buf_release(pSMB);
3233 if (rc == -EAGAIN)
3234 goto findUniqueRetry;
3235
3236 return rc;
3237 }
3238 #endif /* end unused (temporarily) function */
3239
3240 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3241 int
3242 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3243 const char *searchName,
3244 const struct nls_table *nls_codepage,
3245 __u16 * pnetfid,
3246 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
3247 {
3248 /* level 257 SMB_ */
3249 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3250 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3251 T2_FFIRST_RSP_PARMS * parms;
3252 int rc = 0;
3253 int bytes_returned = 0;
3254 int name_len;
3255 __u16 params, byte_count;
3256
3257 cFYI(1, ("In FindFirst for %s",searchName));
3258
3259 findFirstRetry:
3260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3261 (void **) &pSMBr);
3262 if (rc)
3263 return rc;
3264
3265 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3266 name_len =
3267 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
3268 PATH_MAX, nls_codepage, remap);
3269 /* We can not add the asterik earlier in case
3270 it got remapped to 0xF03A as if it were part of the
3271 directory name instead of a wildcard */
3272 name_len *= 2;
3273 pSMB->FileName[name_len] = dirsep;
3274 pSMB->FileName[name_len+1] = 0;
3275 pSMB->FileName[name_len+2] = '*';
3276 pSMB->FileName[name_len+3] = 0;
3277 name_len += 4; /* now the trailing null */
3278 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3279 pSMB->FileName[name_len+1] = 0;
3280 name_len += 2;
3281 } else { /* BB add check for overrun of SMB buf BB */
3282 name_len = strnlen(searchName, PATH_MAX);
3283 /* BB fix here and in unicode clause above ie
3284 if(name_len > buffersize-header)
3285 free buffer exit; BB */
3286 strncpy(pSMB->FileName, searchName, name_len);
3287 pSMB->FileName[name_len] = dirsep;
3288 pSMB->FileName[name_len+1] = '*';
3289 pSMB->FileName[name_len+2] = 0;
3290 name_len += 3;
3291 }
3292
3293 params = 12 + name_len /* includes null */ ;
3294 pSMB->TotalDataCount = 0; /* no EAs */
3295 pSMB->MaxParameterCount = cpu_to_le16(10);
3296 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3297 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3298 pSMB->MaxSetupCount = 0;
3299 pSMB->Reserved = 0;
3300 pSMB->Flags = 0;
3301 pSMB->Timeout = 0;
3302 pSMB->Reserved2 = 0;
3303 byte_count = params + 1 /* pad */ ;
3304 pSMB->TotalParameterCount = cpu_to_le16(params);
3305 pSMB->ParameterCount = pSMB->TotalParameterCount;
3306 pSMB->ParameterOffset = cpu_to_le16(
3307 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3308 - 4);
3309 pSMB->DataCount = 0;
3310 pSMB->DataOffset = 0;
3311 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3312 pSMB->Reserved3 = 0;
3313 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3314 pSMB->SearchAttributes =
3315 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3316 ATTR_DIRECTORY);
3317 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3318 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3319 CIFS_SEARCH_RETURN_RESUME);
3320 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3321
3322 /* BB what should we set StorageType to? Does it matter? BB */
3323 pSMB->SearchStorageType = 0;
3324 pSMB->hdr.smb_buf_length += byte_count;
3325 pSMB->ByteCount = cpu_to_le16(byte_count);
3326
3327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3329 cifs_stats_inc(&tcon->num_ffirst);
3330
3331 if (rc) {/* BB add logic to retry regular search if Unix search
3332 rejected unexpectedly by server */
3333 /* BB Add code to handle unsupported level rc */
3334 cFYI(1, ("Error in FindFirst = %d", rc));
3335
3336 cifs_buf_release(pSMB);
3337
3338 /* BB eventually could optimize out free and realloc of buf */
3339 /* for this case */
3340 if (rc == -EAGAIN)
3341 goto findFirstRetry;
3342 } else { /* decode response */
3343 /* BB remember to free buffer if error BB */
3344 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3345 if(rc == 0) {
3346 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3347 psrch_inf->unicode = TRUE;
3348 else
3349 psrch_inf->unicode = FALSE;
3350
3351 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3352 psrch_inf->smallBuf = 0;
3353 psrch_inf->srch_entries_start =
3354 (char *) &pSMBr->hdr.Protocol +
3355 le16_to_cpu(pSMBr->t2.DataOffset);
3356 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3357 le16_to_cpu(pSMBr->t2.ParameterOffset));
3358
3359 if(parms->EndofSearch)
3360 psrch_inf->endOfSearch = TRUE;
3361 else
3362 psrch_inf->endOfSearch = FALSE;
3363
3364 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3365 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3366 psrch_inf->entries_in_buffer;
3367 *pnetfid = parms->SearchHandle;
3368 } else {
3369 cifs_buf_release(pSMB);
3370 }
3371 }
3372
3373 return rc;
3374 }
3375
3376 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3377 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3378 {
3379 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3380 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3381 T2_FNEXT_RSP_PARMS * parms;
3382 char *response_data;
3383 int rc = 0;
3384 int bytes_returned, name_len;
3385 __u16 params, byte_count;
3386
3387 cFYI(1, ("In FindNext"));
3388
3389 if(psrch_inf->endOfSearch == TRUE)
3390 return -ENOENT;
3391
3392 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3393 (void **) &pSMBr);
3394 if (rc)
3395 return rc;
3396
3397 params = 14; /* includes 2 bytes of null string, converted to LE below */
3398 byte_count = 0;
3399 pSMB->TotalDataCount = 0; /* no EAs */
3400 pSMB->MaxParameterCount = cpu_to_le16(8);
3401 pSMB->MaxDataCount =
3402 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3403 pSMB->MaxSetupCount = 0;
3404 pSMB->Reserved = 0;
3405 pSMB->Flags = 0;
3406 pSMB->Timeout = 0;
3407 pSMB->Reserved2 = 0;
3408 pSMB->ParameterOffset = cpu_to_le16(
3409 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3410 pSMB->DataCount = 0;
3411 pSMB->DataOffset = 0;
3412 pSMB->SetupCount = 1;
3413 pSMB->Reserved3 = 0;
3414 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3415 pSMB->SearchHandle = searchHandle; /* always kept as le */
3416 pSMB->SearchCount =
3417 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3418 /* test for Unix extensions */
3419 /* if (tcon->ses->capabilities & CAP_UNIX) {
3420 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3421 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3422 } else {
3423 pSMB->InformationLevel =
3424 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3425 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3426 } */
3427 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3428 pSMB->ResumeKey = psrch_inf->resume_key;
3429 pSMB->SearchFlags =
3430 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3431
3432 name_len = psrch_inf->resume_name_len;
3433 params += name_len;
3434 if(name_len < PATH_MAX) {
3435 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3436 byte_count += name_len;
3437 /* 14 byte parm len above enough for 2 byte null terminator */
3438 pSMB->ResumeFileName[name_len] = 0;
3439 pSMB->ResumeFileName[name_len+1] = 0;
3440 } else {
3441 rc = -EINVAL;
3442 goto FNext2_err_exit;
3443 }
3444 byte_count = params + 1 /* pad */ ;
3445 pSMB->TotalParameterCount = cpu_to_le16(params);
3446 pSMB->ParameterCount = pSMB->TotalParameterCount;
3447 pSMB->hdr.smb_buf_length += byte_count;
3448 pSMB->ByteCount = cpu_to_le16(byte_count);
3449
3450 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3451 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3452 cifs_stats_inc(&tcon->num_fnext);
3453 if (rc) {
3454 if (rc == -EBADF) {
3455 psrch_inf->endOfSearch = TRUE;
3456 rc = 0; /* search probably was closed at end of search above */
3457 } else
3458 cFYI(1, ("FindNext returned = %d", rc));
3459 } else { /* decode response */
3460 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3461
3462 if(rc == 0) {
3463 /* BB fixme add lock for file (srch_info) struct here */
3464 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3465 psrch_inf->unicode = TRUE;
3466 else
3467 psrch_inf->unicode = FALSE;
3468 response_data = (char *) &pSMBr->hdr.Protocol +
3469 le16_to_cpu(pSMBr->t2.ParameterOffset);
3470 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3471 response_data = (char *)&pSMBr->hdr.Protocol +
3472 le16_to_cpu(pSMBr->t2.DataOffset);
3473 if(psrch_inf->smallBuf)
3474 cifs_small_buf_release(
3475 psrch_inf->ntwrk_buf_start);
3476 else
3477 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3478 psrch_inf->srch_entries_start = response_data;
3479 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3480 psrch_inf->smallBuf = 0;
3481 if(parms->EndofSearch)
3482 psrch_inf->endOfSearch = TRUE;
3483 else
3484 psrch_inf->endOfSearch = FALSE;
3485
3486 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3487 psrch_inf->index_of_last_entry +=
3488 psrch_inf->entries_in_buffer;
3489 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3490
3491 /* BB fixme add unlock here */
3492 }
3493
3494 }
3495
3496 /* BB On error, should we leave previous search buf (and count and
3497 last entry fields) intact or free the previous one? */
3498
3499 /* Note: On -EAGAIN error only caller can retry on handle based calls
3500 since file handle passed in no longer valid */
3501 FNext2_err_exit:
3502 if (rc != 0)
3503 cifs_buf_release(pSMB);
3504
3505 return rc;
3506 }
3507
3508 int
3509 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3510 {
3511 int rc = 0;
3512 FINDCLOSE_REQ *pSMB = NULL;
3513 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3514 int bytes_returned;
3515
3516 cFYI(1, ("In CIFSSMBFindClose"));
3517 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3518
3519 /* no sense returning error if session restarted
3520 as file handle has been closed */
3521 if(rc == -EAGAIN)
3522 return 0;
3523 if (rc)
3524 return rc;
3525
3526 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3527 pSMB->FileID = searchHandle;
3528 pSMB->ByteCount = 0;
3529 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3530 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3531 if (rc) {
3532 cERROR(1, ("Send error in FindClose = %d", rc));
3533 }
3534 cifs_stats_inc(&tcon->num_fclose);
3535 cifs_small_buf_release(pSMB);
3536
3537 /* Since session is dead, search handle closed on server already */
3538 if (rc == -EAGAIN)
3539 rc = 0;
3540
3541 return rc;
3542 }
3543
3544 int
3545 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3546 const unsigned char *searchName,
3547 __u64 * inode_number,
3548 const struct nls_table *nls_codepage, int remap)
3549 {
3550 int rc = 0;
3551 TRANSACTION2_QPI_REQ *pSMB = NULL;
3552 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3553 int name_len, bytes_returned;
3554 __u16 params, byte_count;
3555
3556 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3557 if(tcon == NULL)
3558 return -ENODEV;
3559
3560 GetInodeNumberRetry:
3561 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3562 (void **) &pSMBr);
3563 if (rc)
3564 return rc;
3565
3566
3567 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3568 name_len =
3569 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3570 PATH_MAX,nls_codepage, remap);
3571 name_len++; /* trailing null */
3572 name_len *= 2;
3573 } else { /* BB improve the check for buffer overruns BB */
3574 name_len = strnlen(searchName, PATH_MAX);
3575 name_len++; /* trailing null */
3576 strncpy(pSMB->FileName, searchName, name_len);
3577 }
3578
3579 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3580 pSMB->TotalDataCount = 0;
3581 pSMB->MaxParameterCount = cpu_to_le16(2);
3582 /* BB find exact max data count below from sess structure BB */
3583 pSMB->MaxDataCount = cpu_to_le16(4000);
3584 pSMB->MaxSetupCount = 0;
3585 pSMB->Reserved = 0;
3586 pSMB->Flags = 0;
3587 pSMB->Timeout = 0;
3588 pSMB->Reserved2 = 0;
3589 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3590 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3591 pSMB->DataCount = 0;
3592 pSMB->DataOffset = 0;
3593 pSMB->SetupCount = 1;
3594 pSMB->Reserved3 = 0;
3595 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3596 byte_count = params + 1 /* pad */ ;
3597 pSMB->TotalParameterCount = cpu_to_le16(params);
3598 pSMB->ParameterCount = pSMB->TotalParameterCount;
3599 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3600 pSMB->Reserved4 = 0;
3601 pSMB->hdr.smb_buf_length += byte_count;
3602 pSMB->ByteCount = cpu_to_le16(byte_count);
3603
3604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3606 if (rc) {
3607 cFYI(1, ("error %d in QueryInternalInfo", rc));
3608 } else {
3609 /* decode response */
3610 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3611 if (rc || (pSMBr->ByteCount < 2))
3612 /* BB also check enough total bytes returned */
3613 /* If rc should we check for EOPNOSUPP and
3614 disable the srvino flag? or in caller? */
3615 rc = -EIO; /* bad smb */
3616 else {
3617 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3618 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3619 struct file_internal_info * pfinfo;
3620 /* BB Do we need a cast or hash here ? */
3621 if(count < 8) {
3622 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3623 rc = -EIO;
3624 goto GetInodeNumOut;
3625 }
3626 pfinfo = (struct file_internal_info *)
3627 (data_offset + (char *) &pSMBr->hdr.Protocol);
3628 *inode_number = pfinfo->UniqueId;
3629 }
3630 }
3631 GetInodeNumOut:
3632 cifs_buf_release(pSMB);
3633 if (rc == -EAGAIN)
3634 goto GetInodeNumberRetry;
3635 return rc;
3636 }
3637
3638 int
3639 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3640 const unsigned char *searchName,
3641 unsigned char **targetUNCs,
3642 unsigned int *number_of_UNC_in_array,
3643 const struct nls_table *nls_codepage, int remap)
3644 {
3645 /* TRANS2_GET_DFS_REFERRAL */
3646 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3647 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3648 struct dfs_referral_level_3 * referrals = NULL;
3649 int rc = 0;
3650 int bytes_returned;
3651 int name_len;
3652 unsigned int i;
3653 char * temp;
3654 __u16 params, byte_count;
3655 *number_of_UNC_in_array = 0;
3656 *targetUNCs = NULL;
3657
3658 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3659 if (ses == NULL)
3660 return -ENODEV;
3661 getDFSRetry:
3662 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3663 (void **) &pSMBr);
3664 if (rc)
3665 return rc;
3666
3667 /* server pointer checked in called function,
3668 but should never be null here anyway */
3669 pSMB->hdr.Mid = GetNextMid(ses->server);
3670 pSMB->hdr.Tid = ses->ipc_tid;
3671 pSMB->hdr.Uid = ses->Suid;
3672 if (ses->capabilities & CAP_STATUS32) {
3673 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3674 }
3675 if (ses->capabilities & CAP_DFS) {
3676 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3677 }
3678
3679 if (ses->capabilities & CAP_UNICODE) {
3680 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3681 name_len =
3682 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3683 searchName, PATH_MAX, nls_codepage, remap);
3684 name_len++; /* trailing null */
3685 name_len *= 2;
3686 } else { /* BB improve the check for buffer overruns BB */
3687 name_len = strnlen(searchName, PATH_MAX);
3688 name_len++; /* trailing null */
3689 strncpy(pSMB->RequestFileName, searchName, name_len);
3690 }
3691
3692 if(ses->server) {
3693 if(ses->server->secMode &
3694 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3695 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3696 }
3697
3698 pSMB->hdr.Uid = ses->Suid;
3699
3700 params = 2 /* level */ + name_len /*includes null */ ;
3701 pSMB->TotalDataCount = 0;
3702 pSMB->DataCount = 0;
3703 pSMB->DataOffset = 0;
3704 pSMB->MaxParameterCount = 0;
3705 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3706 pSMB->MaxSetupCount = 0;
3707 pSMB->Reserved = 0;
3708 pSMB->Flags = 0;
3709 pSMB->Timeout = 0;
3710 pSMB->Reserved2 = 0;
3711 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3712 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3713 pSMB->SetupCount = 1;
3714 pSMB->Reserved3 = 0;
3715 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3716 byte_count = params + 3 /* pad */ ;
3717 pSMB->ParameterCount = cpu_to_le16(params);
3718 pSMB->TotalParameterCount = pSMB->ParameterCount;
3719 pSMB->MaxReferralLevel = cpu_to_le16(3);
3720 pSMB->hdr.smb_buf_length += byte_count;
3721 pSMB->ByteCount = cpu_to_le16(byte_count);
3722
3723 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3725 if (rc) {
3726 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3727 } else { /* decode response */
3728 /* BB Add logic to parse referrals here */
3729 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3730
3731 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3732 rc = -EIO; /* bad smb */
3733 else {
3734 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3735 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3736
3737 cFYI(1,
3738 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3739 pSMBr->ByteCount, data_offset));
3740 referrals =
3741 (struct dfs_referral_level_3 *)
3742 (8 /* sizeof start of data block */ +
3743 data_offset +
3744 (char *) &pSMBr->hdr.Protocol);
3745 cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
3746 le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
3747 /* BB This field is actually two bytes in from start of
3748 data block so we could do safety check that DataBlock
3749 begins at address of pSMBr->NumberOfReferrals */
3750 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3751
3752 /* BB Fix below so can return more than one referral */
3753 if(*number_of_UNC_in_array > 1)
3754 *number_of_UNC_in_array = 1;
3755
3756 /* get the length of the strings describing refs */
3757 name_len = 0;
3758 for(i=0;i<*number_of_UNC_in_array;i++) {
3759 /* make sure that DfsPathOffset not past end */
3760 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3761 if (offset > data_count) {
3762 /* if invalid referral, stop here and do
3763 not try to copy any more */
3764 *number_of_UNC_in_array = i;
3765 break;
3766 }
3767 temp = ((char *)referrals) + offset;
3768
3769 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3770 name_len += UniStrnlen((wchar_t *)temp,data_count);
3771 } else {
3772 name_len += strnlen(temp,data_count);
3773 }
3774 referrals++;
3775 /* BB add check that referral pointer does not fall off end PDU */
3776
3777 }
3778 /* BB add check for name_len bigger than bcc */
3779 *targetUNCs =
3780 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3781 if(*targetUNCs == NULL) {
3782 rc = -ENOMEM;
3783 goto GetDFSRefExit;
3784 }
3785 /* copy the ref strings */
3786 referrals =
3787 (struct dfs_referral_level_3 *)
3788 (8 /* sizeof data hdr */ +
3789 data_offset +
3790 (char *) &pSMBr->hdr.Protocol);
3791
3792 for(i=0;i<*number_of_UNC_in_array;i++) {
3793 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3794 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3795 cifs_strfromUCS_le(*targetUNCs,
3796 (__le16 *) temp, name_len, nls_codepage);
3797 } else {
3798 strncpy(*targetUNCs,temp,name_len);
3799 }
3800 /* BB update target_uncs pointers */
3801 referrals++;
3802 }
3803 temp = *targetUNCs;
3804 temp[name_len] = 0;
3805 }
3806
3807 }
3808 GetDFSRefExit:
3809 if (pSMB)
3810 cifs_buf_release(pSMB);
3811
3812 if (rc == -EAGAIN)
3813 goto getDFSRetry;
3814
3815 return rc;
3816 }
3817
3818 /* Query File System Info such as free space to old servers such as Win 9x */
3819 int
3820 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3821 {
3822 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3823 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3824 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3825 FILE_SYSTEM_ALLOC_INFO *response_data;
3826 int rc = 0;
3827 int bytes_returned = 0;
3828 __u16 params, byte_count;
3829
3830 cFYI(1, ("OldQFSInfo"));
3831 oldQFSInfoRetry:
3832 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3833 (void **) &pSMBr);
3834 if (rc)
3835 return rc;
3836 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3837 (void **) &pSMBr);
3838 if (rc)
3839 return rc;
3840
3841 params = 2; /* level */
3842 pSMB->TotalDataCount = 0;
3843 pSMB->MaxParameterCount = cpu_to_le16(2);
3844 pSMB->MaxDataCount = cpu_to_le16(1000);
3845 pSMB->MaxSetupCount = 0;
3846 pSMB->Reserved = 0;
3847 pSMB->Flags = 0;
3848 pSMB->Timeout = 0;
3849 pSMB->Reserved2 = 0;
3850 byte_count = params + 1 /* pad */ ;
3851 pSMB->TotalParameterCount = cpu_to_le16(params);
3852 pSMB->ParameterCount = pSMB->TotalParameterCount;
3853 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3854 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3855 pSMB->DataCount = 0;
3856 pSMB->DataOffset = 0;
3857 pSMB->SetupCount = 1;
3858 pSMB->Reserved3 = 0;
3859 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3860 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3861 pSMB->hdr.smb_buf_length += byte_count;
3862 pSMB->ByteCount = cpu_to_le16(byte_count);
3863
3864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3866 if (rc) {
3867 cFYI(1, ("Send error in QFSInfo = %d", rc));
3868 } else { /* decode response */
3869 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3870
3871 if (rc || (pSMBr->ByteCount < 18))
3872 rc = -EIO; /* bad smb */
3873 else {
3874 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3875 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3876 pSMBr->ByteCount, data_offset));
3877
3878 response_data =
3879 (FILE_SYSTEM_ALLOC_INFO *)
3880 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3881 FSData->f_bsize =
3882 le16_to_cpu(response_data->BytesPerSector) *
3883 le32_to_cpu(response_data->
3884 SectorsPerAllocationUnit);
3885 FSData->f_blocks =
3886 le32_to_cpu(response_data->TotalAllocationUnits);
3887 FSData->f_bfree = FSData->f_bavail =
3888 le32_to_cpu(response_data->FreeAllocationUnits);
3889 cFYI(1,
3890 ("Blocks: %lld Free: %lld Block size %ld",
3891 (unsigned long long)FSData->f_blocks,
3892 (unsigned long long)FSData->f_bfree,
3893 FSData->f_bsize));
3894 }
3895 }
3896 cifs_buf_release(pSMB);
3897
3898 if (rc == -EAGAIN)
3899 goto oldQFSInfoRetry;
3900
3901 return rc;
3902 }
3903
3904 int
3905 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3906 {
3907 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3908 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3909 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3910 FILE_SYSTEM_INFO *response_data;
3911 int rc = 0;
3912 int bytes_returned = 0;
3913 __u16 params, byte_count;
3914
3915 cFYI(1, ("In QFSInfo"));
3916 QFSInfoRetry:
3917 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3918 (void **) &pSMBr);
3919 if (rc)
3920 return rc;
3921
3922 params = 2; /* level */
3923 pSMB->TotalDataCount = 0;
3924 pSMB->MaxParameterCount = cpu_to_le16(2);
3925 pSMB->MaxDataCount = cpu_to_le16(1000);
3926 pSMB->MaxSetupCount = 0;
3927 pSMB->Reserved = 0;
3928 pSMB->Flags = 0;
3929 pSMB->Timeout = 0;
3930 pSMB->Reserved2 = 0;
3931 byte_count = params + 1 /* pad */ ;
3932 pSMB->TotalParameterCount = cpu_to_le16(params);
3933 pSMB->ParameterCount = pSMB->TotalParameterCount;
3934 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3935 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3936 pSMB->DataCount = 0;
3937 pSMB->DataOffset = 0;
3938 pSMB->SetupCount = 1;
3939 pSMB->Reserved3 = 0;
3940 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3941 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3942 pSMB->hdr.smb_buf_length += byte_count;
3943 pSMB->ByteCount = cpu_to_le16(byte_count);
3944
3945 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3946 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3947 if (rc) {
3948 cFYI(1, ("Send error in QFSInfo = %d", rc));
3949 } else { /* decode response */
3950 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3951
3952 if (rc || (pSMBr->ByteCount < 24))
3953 rc = -EIO; /* bad smb */
3954 else {
3955 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3956
3957 response_data =
3958 (FILE_SYSTEM_INFO
3959 *) (((char *) &pSMBr->hdr.Protocol) +
3960 data_offset);
3961 FSData->f_bsize =
3962 le32_to_cpu(response_data->BytesPerSector) *
3963 le32_to_cpu(response_data->
3964 SectorsPerAllocationUnit);
3965 FSData->f_blocks =
3966 le64_to_cpu(response_data->TotalAllocationUnits);
3967 FSData->f_bfree = FSData->f_bavail =
3968 le64_to_cpu(response_data->FreeAllocationUnits);
3969 cFYI(1,
3970 ("Blocks: %lld Free: %lld Block size %ld",
3971 (unsigned long long)FSData->f_blocks,
3972 (unsigned long long)FSData->f_bfree,
3973 FSData->f_bsize));
3974 }
3975 }
3976 cifs_buf_release(pSMB);
3977
3978 if (rc == -EAGAIN)
3979 goto QFSInfoRetry;
3980
3981 return rc;
3982 }
3983
3984 int
3985 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3986 {
3987 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3988 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3989 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3990 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3991 int rc = 0;
3992 int bytes_returned = 0;
3993 __u16 params, byte_count;
3994
3995 cFYI(1, ("In QFSAttributeInfo"));
3996 QFSAttributeRetry:
3997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3998 (void **) &pSMBr);
3999 if (rc)
4000 return rc;
4001
4002 params = 2; /* level */
4003 pSMB->TotalDataCount = 0;
4004 pSMB->MaxParameterCount = cpu_to_le16(2);
4005 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4006 pSMB->MaxSetupCount = 0;
4007 pSMB->Reserved = 0;
4008 pSMB->Flags = 0;
4009 pSMB->Timeout = 0;
4010 pSMB->Reserved2 = 0;
4011 byte_count = params + 1 /* pad */ ;
4012 pSMB->TotalParameterCount = cpu_to_le16(params);
4013 pSMB->ParameterCount = pSMB->TotalParameterCount;
4014 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4015 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4016 pSMB->DataCount = 0;
4017 pSMB->DataOffset = 0;
4018 pSMB->SetupCount = 1;
4019 pSMB->Reserved3 = 0;
4020 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4021 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4022 pSMB->hdr.smb_buf_length += byte_count;
4023 pSMB->ByteCount = cpu_to_le16(byte_count);
4024
4025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4027 if (rc) {
4028 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4029 } else { /* decode response */
4030 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4031
4032 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4033 rc = -EIO; /* bad smb */
4034 } else {
4035 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4036 response_data =
4037 (FILE_SYSTEM_ATTRIBUTE_INFO
4038 *) (((char *) &pSMBr->hdr.Protocol) +
4039 data_offset);
4040 memcpy(&tcon->fsAttrInfo, response_data,
4041 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4042 }
4043 }
4044 cifs_buf_release(pSMB);
4045
4046 if (rc == -EAGAIN)
4047 goto QFSAttributeRetry;
4048
4049 return rc;
4050 }
4051
4052 int
4053 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4054 {
4055 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4056 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4057 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4058 FILE_SYSTEM_DEVICE_INFO *response_data;
4059 int rc = 0;
4060 int bytes_returned = 0;
4061 __u16 params, byte_count;
4062
4063 cFYI(1, ("In QFSDeviceInfo"));
4064 QFSDeviceRetry:
4065 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4066 (void **) &pSMBr);
4067 if (rc)
4068 return rc;
4069
4070 params = 2; /* level */
4071 pSMB->TotalDataCount = 0;
4072 pSMB->MaxParameterCount = cpu_to_le16(2);
4073 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4074 pSMB->MaxSetupCount = 0;
4075 pSMB->Reserved = 0;
4076 pSMB->Flags = 0;
4077 pSMB->Timeout = 0;
4078 pSMB->Reserved2 = 0;
4079 byte_count = params + 1 /* pad */ ;
4080 pSMB->TotalParameterCount = cpu_to_le16(params);
4081 pSMB->ParameterCount = pSMB->TotalParameterCount;
4082 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4083 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4084
4085 pSMB->DataCount = 0;
4086 pSMB->DataOffset = 0;
4087 pSMB->SetupCount = 1;
4088 pSMB->Reserved3 = 0;
4089 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4090 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4091 pSMB->hdr.smb_buf_length += byte_count;
4092 pSMB->ByteCount = cpu_to_le16(byte_count);
4093
4094 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4095 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4096 if (rc) {
4097 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4098 } else { /* decode response */
4099 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4100
4101 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4102 rc = -EIO; /* bad smb */
4103 else {
4104 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4105 response_data =
4106 (FILE_SYSTEM_DEVICE_INFO *)
4107 (((char *) &pSMBr->hdr.Protocol) +
4108 data_offset);
4109 memcpy(&tcon->fsDevInfo, response_data,
4110 sizeof (FILE_SYSTEM_DEVICE_INFO));
4111 }
4112 }
4113 cifs_buf_release(pSMB);
4114
4115 if (rc == -EAGAIN)
4116 goto QFSDeviceRetry;
4117
4118 return rc;
4119 }
4120
4121 int
4122 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4123 {
4124 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4125 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4126 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4127 FILE_SYSTEM_UNIX_INFO *response_data;
4128 int rc = 0;
4129 int bytes_returned = 0;
4130 __u16 params, byte_count;
4131
4132 cFYI(1, ("In QFSUnixInfo"));
4133 QFSUnixRetry:
4134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4135 (void **) &pSMBr);
4136 if (rc)
4137 return rc;
4138
4139 params = 2; /* level */
4140 pSMB->TotalDataCount = 0;
4141 pSMB->DataCount = 0;
4142 pSMB->DataOffset = 0;
4143 pSMB->MaxParameterCount = cpu_to_le16(2);
4144 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4145 pSMB->MaxSetupCount = 0;
4146 pSMB->Reserved = 0;
4147 pSMB->Flags = 0;
4148 pSMB->Timeout = 0;
4149 pSMB->Reserved2 = 0;
4150 byte_count = params + 1 /* pad */ ;
4151 pSMB->ParameterCount = cpu_to_le16(params);
4152 pSMB->TotalParameterCount = pSMB->ParameterCount;
4153 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4154 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4155 pSMB->SetupCount = 1;
4156 pSMB->Reserved3 = 0;
4157 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4158 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4159 pSMB->hdr.smb_buf_length += byte_count;
4160 pSMB->ByteCount = cpu_to_le16(byte_count);
4161
4162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4164 if (rc) {
4165 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4166 } else { /* decode response */
4167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4168
4169 if (rc || (pSMBr->ByteCount < 13)) {
4170 rc = -EIO; /* bad smb */
4171 } else {
4172 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4173 response_data =
4174 (FILE_SYSTEM_UNIX_INFO
4175 *) (((char *) &pSMBr->hdr.Protocol) +
4176 data_offset);
4177 memcpy(&tcon->fsUnixInfo, response_data,
4178 sizeof (FILE_SYSTEM_UNIX_INFO));
4179 }
4180 }
4181 cifs_buf_release(pSMB);
4182
4183 if (rc == -EAGAIN)
4184 goto QFSUnixRetry;
4185
4186
4187 return rc;
4188 }
4189
4190 int
4191 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4192 {
4193 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4194 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4195 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4196 int rc = 0;
4197 int bytes_returned = 0;
4198 __u16 params, param_offset, offset, byte_count;
4199
4200 cFYI(1, ("In SETFSUnixInfo"));
4201 SETFSUnixRetry:
4202 /* BB switch to small buf init to save memory */
4203 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4204 (void **) &pSMBr);
4205 if (rc)
4206 return rc;
4207
4208 params = 4; /* 2 bytes zero followed by info level. */
4209 pSMB->MaxSetupCount = 0;
4210 pSMB->Reserved = 0;
4211 pSMB->Flags = 0;
4212 pSMB->Timeout = 0;
4213 pSMB->Reserved2 = 0;
4214 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4215 offset = param_offset + params;
4216
4217 pSMB->MaxParameterCount = cpu_to_le16(4);
4218 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4219 pSMB->SetupCount = 1;
4220 pSMB->Reserved3 = 0;
4221 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4222 byte_count = 1 /* pad */ + params + 12;
4223
4224 pSMB->DataCount = cpu_to_le16(12);
4225 pSMB->ParameterCount = cpu_to_le16(params);
4226 pSMB->TotalDataCount = pSMB->DataCount;
4227 pSMB->TotalParameterCount = pSMB->ParameterCount;
4228 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4229 pSMB->DataOffset = cpu_to_le16(offset);
4230
4231 /* Params. */
4232 pSMB->FileNum = 0;
4233 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4234
4235 /* Data. */
4236 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4237 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4238 pSMB->ClientUnixCap = cpu_to_le64(cap);
4239
4240 pSMB->hdr.smb_buf_length += byte_count;
4241 pSMB->ByteCount = cpu_to_le16(byte_count);
4242
4243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4245 if (rc) {
4246 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4247 } else { /* decode response */
4248 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4249 if (rc) {
4250 rc = -EIO; /* bad smb */
4251 }
4252 }
4253 cifs_buf_release(pSMB);
4254
4255 if (rc == -EAGAIN)
4256 goto SETFSUnixRetry;
4257
4258 return rc;
4259 }
4260
4261
4262
4263 int
4264 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4265 struct kstatfs *FSData)
4266 {
4267 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4268 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4269 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4270 FILE_SYSTEM_POSIX_INFO *response_data;
4271 int rc = 0;
4272 int bytes_returned = 0;
4273 __u16 params, byte_count;
4274
4275 cFYI(1, ("In QFSPosixInfo"));
4276 QFSPosixRetry:
4277 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4278 (void **) &pSMBr);
4279 if (rc)
4280 return rc;
4281
4282 params = 2; /* level */
4283 pSMB->TotalDataCount = 0;
4284 pSMB->DataCount = 0;
4285 pSMB->DataOffset = 0;
4286 pSMB->MaxParameterCount = cpu_to_le16(2);
4287 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4288 pSMB->MaxSetupCount = 0;
4289 pSMB->Reserved = 0;
4290 pSMB->Flags = 0;
4291 pSMB->Timeout = 0;
4292 pSMB->Reserved2 = 0;
4293 byte_count = params + 1 /* pad */ ;
4294 pSMB->ParameterCount = cpu_to_le16(params);
4295 pSMB->TotalParameterCount = pSMB->ParameterCount;
4296 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4297 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4298 pSMB->SetupCount = 1;
4299 pSMB->Reserved3 = 0;
4300 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4301 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4302 pSMB->hdr.smb_buf_length += byte_count;
4303 pSMB->ByteCount = cpu_to_le16(byte_count);
4304
4305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4307 if (rc) {
4308 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4309 } else { /* decode response */
4310 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4311
4312 if (rc || (pSMBr->ByteCount < 13)) {
4313 rc = -EIO; /* bad smb */
4314 } else {
4315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4316 response_data =
4317 (FILE_SYSTEM_POSIX_INFO
4318 *) (((char *) &pSMBr->hdr.Protocol) +
4319 data_offset);
4320 FSData->f_bsize =
4321 le32_to_cpu(response_data->BlockSize);
4322 FSData->f_blocks =
4323 le64_to_cpu(response_data->TotalBlocks);
4324 FSData->f_bfree =
4325 le64_to_cpu(response_data->BlocksAvail);
4326 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4327 FSData->f_bavail = FSData->f_bfree;
4328 } else {
4329 FSData->f_bavail =
4330 le64_to_cpu(response_data->UserBlocksAvail);
4331 }
4332 if(response_data->TotalFileNodes != cpu_to_le64(-1))
4333 FSData->f_files =
4334 le64_to_cpu(response_data->TotalFileNodes);
4335 if(response_data->FreeFileNodes != cpu_to_le64(-1))
4336 FSData->f_ffree =
4337 le64_to_cpu(response_data->FreeFileNodes);
4338 }
4339 }
4340 cifs_buf_release(pSMB);
4341
4342 if (rc == -EAGAIN)
4343 goto QFSPosixRetry;
4344
4345 return rc;
4346 }
4347
4348
4349 /* We can not use write of zero bytes trick to
4350 set file size due to need for large file support. Also note that
4351 this SetPathInfo is preferred to SetFileInfo based method in next
4352 routine which is only needed to work around a sharing violation bug
4353 in Samba which this routine can run into */
4354
4355 int
4356 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4357 __u64 size, int SetAllocation,
4358 const struct nls_table *nls_codepage, int remap)
4359 {
4360 struct smb_com_transaction2_spi_req *pSMB = NULL;
4361 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4362 struct file_end_of_file_info *parm_data;
4363 int name_len;
4364 int rc = 0;
4365 int bytes_returned = 0;
4366 __u16 params, byte_count, data_count, param_offset, offset;
4367
4368 cFYI(1, ("In SetEOF"));
4369 SetEOFRetry:
4370 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4371 (void **) &pSMBr);
4372 if (rc)
4373 return rc;
4374
4375 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4376 name_len =
4377 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4378 PATH_MAX, nls_codepage, remap);
4379 name_len++; /* trailing null */
4380 name_len *= 2;
4381 } else { /* BB improve the check for buffer overruns BB */
4382 name_len = strnlen(fileName, PATH_MAX);
4383 name_len++; /* trailing null */
4384 strncpy(pSMB->FileName, fileName, name_len);
4385 }
4386 params = 6 + name_len;
4387 data_count = sizeof (struct file_end_of_file_info);
4388 pSMB->MaxParameterCount = cpu_to_le16(2);
4389 pSMB->MaxDataCount = cpu_to_le16(4100);
4390 pSMB->MaxSetupCount = 0;
4391 pSMB->Reserved = 0;
4392 pSMB->Flags = 0;
4393 pSMB->Timeout = 0;
4394 pSMB->Reserved2 = 0;
4395 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4396 InformationLevel) - 4;
4397 offset = param_offset + params;
4398 if(SetAllocation) {
4399 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4400 pSMB->InformationLevel =
4401 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4402 else
4403 pSMB->InformationLevel =
4404 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4405 } else /* Set File Size */ {
4406 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4407 pSMB->InformationLevel =
4408 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4409 else
4410 pSMB->InformationLevel =
4411 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4412 }
4413
4414 parm_data =
4415 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4416 offset);
4417 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4418 pSMB->DataOffset = cpu_to_le16(offset);
4419 pSMB->SetupCount = 1;
4420 pSMB->Reserved3 = 0;
4421 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4422 byte_count = 3 /* pad */ + params + data_count;
4423 pSMB->DataCount = cpu_to_le16(data_count);
4424 pSMB->TotalDataCount = pSMB->DataCount;
4425 pSMB->ParameterCount = cpu_to_le16(params);
4426 pSMB->TotalParameterCount = pSMB->ParameterCount;
4427 pSMB->Reserved4 = 0;
4428 pSMB->hdr.smb_buf_length += byte_count;
4429 parm_data->FileSize = cpu_to_le64(size);
4430 pSMB->ByteCount = cpu_to_le16(byte_count);
4431 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4432 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4433 if (rc) {
4434 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4435 }
4436
4437 cifs_buf_release(pSMB);
4438
4439 if (rc == -EAGAIN)
4440 goto SetEOFRetry;
4441
4442 return rc;
4443 }
4444
4445 int
4446 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4447 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4448 {
4449 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4450 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4451 char *data_offset;
4452 struct file_end_of_file_info *parm_data;
4453 int rc = 0;
4454 int bytes_returned = 0;
4455 __u16 params, param_offset, offset, byte_count, count;
4456
4457 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4458 (long long)size));
4459 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4460
4461 if (rc)
4462 return rc;
4463
4464 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4465
4466 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4467 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4468
4469 params = 6;
4470 pSMB->MaxSetupCount = 0;
4471 pSMB->Reserved = 0;
4472 pSMB->Flags = 0;
4473 pSMB->Timeout = 0;
4474 pSMB->Reserved2 = 0;
4475 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4476 offset = param_offset + params;
4477
4478 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4479
4480 count = sizeof(struct file_end_of_file_info);
4481 pSMB->MaxParameterCount = cpu_to_le16(2);
4482 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4483 pSMB->SetupCount = 1;
4484 pSMB->Reserved3 = 0;
4485 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4486 byte_count = 3 /* pad */ + params + count;
4487 pSMB->DataCount = cpu_to_le16(count);
4488 pSMB->ParameterCount = cpu_to_le16(params);
4489 pSMB->TotalDataCount = pSMB->DataCount;
4490 pSMB->TotalParameterCount = pSMB->ParameterCount;
4491 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4492 parm_data =
4493 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4494 offset);
4495 pSMB->DataOffset = cpu_to_le16(offset);
4496 parm_data->FileSize = cpu_to_le64(size);
4497 pSMB->Fid = fid;
4498 if(SetAllocation) {
4499 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4500 pSMB->InformationLevel =
4501 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4502 else
4503 pSMB->InformationLevel =
4504 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4505 } else /* Set File Size */ {
4506 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4507 pSMB->InformationLevel =
4508 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4509 else
4510 pSMB->InformationLevel =
4511 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4512 }
4513 pSMB->Reserved4 = 0;
4514 pSMB->hdr.smb_buf_length += byte_count;
4515 pSMB->ByteCount = cpu_to_le16(byte_count);
4516 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4517 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4518 if (rc) {
4519 cFYI(1,
4520 ("Send error in SetFileInfo (SetFileSize) = %d",
4521 rc));
4522 }
4523
4524 if (pSMB)
4525 cifs_small_buf_release(pSMB);
4526
4527 /* Note: On -EAGAIN error only caller can retry on handle based calls
4528 since file handle passed in no longer valid */
4529
4530 return rc;
4531 }
4532
4533 /* Some legacy servers such as NT4 require that the file times be set on
4534 an open handle, rather than by pathname - this is awkward due to
4535 potential access conflicts on the open, but it is unavoidable for these
4536 old servers since the only other choice is to go from 100 nanosecond DCE
4537 time and resort to the original setpathinfo level which takes the ancient
4538 DOS time format with 2 second granularity */
4539 int
4540 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4541 __u16 fid)
4542 {
4543 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4544 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4545 char *data_offset;
4546 int rc = 0;
4547 int bytes_returned = 0;
4548 __u16 params, param_offset, offset, byte_count, count;
4549
4550 cFYI(1, ("Set Times (via SetFileInfo)"));
4551 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4552
4553 if (rc)
4554 return rc;
4555
4556 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4557
4558 /* At this point there is no need to override the current pid
4559 with the pid of the opener, but that could change if we someday
4560 use an existing handle (rather than opening one on the fly) */
4561 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4562 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4563
4564 params = 6;
4565 pSMB->MaxSetupCount = 0;
4566 pSMB->Reserved = 0;
4567 pSMB->Flags = 0;
4568 pSMB->Timeout = 0;
4569 pSMB->Reserved2 = 0;
4570 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4571 offset = param_offset + params;
4572
4573 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4574
4575 count = sizeof (FILE_BASIC_INFO);
4576 pSMB->MaxParameterCount = cpu_to_le16(2);
4577 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4578 pSMB->SetupCount = 1;
4579 pSMB->Reserved3 = 0;
4580 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4581 byte_count = 3 /* pad */ + params + count;
4582 pSMB->DataCount = cpu_to_le16(count);
4583 pSMB->ParameterCount = cpu_to_le16(params);
4584 pSMB->TotalDataCount = pSMB->DataCount;
4585 pSMB->TotalParameterCount = pSMB->ParameterCount;
4586 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4587 pSMB->DataOffset = cpu_to_le16(offset);
4588 pSMB->Fid = fid;
4589 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4590 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4591 else
4592 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4593 pSMB->Reserved4 = 0;
4594 pSMB->hdr.smb_buf_length += byte_count;
4595 pSMB->ByteCount = cpu_to_le16(byte_count);
4596 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4597 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4598 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4599 if (rc) {
4600 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4601 }
4602
4603 cifs_small_buf_release(pSMB);
4604
4605 /* Note: On -EAGAIN error only caller can retry on handle based calls
4606 since file handle passed in no longer valid */
4607
4608 return rc;
4609 }
4610
4611
4612 int
4613 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4614 const FILE_BASIC_INFO * data,
4615 const struct nls_table *nls_codepage, int remap)
4616 {
4617 TRANSACTION2_SPI_REQ *pSMB = NULL;
4618 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4619 int name_len;
4620 int rc = 0;
4621 int bytes_returned = 0;
4622 char *data_offset;
4623 __u16 params, param_offset, offset, byte_count, count;
4624
4625 cFYI(1, ("In SetTimes"));
4626
4627 SetTimesRetry:
4628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4629 (void **) &pSMBr);
4630 if (rc)
4631 return rc;
4632
4633 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4634 name_len =
4635 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4636 PATH_MAX, nls_codepage, remap);
4637 name_len++; /* trailing null */
4638 name_len *= 2;
4639 } else { /* BB improve the check for buffer overruns BB */
4640 name_len = strnlen(fileName, PATH_MAX);
4641 name_len++; /* trailing null */
4642 strncpy(pSMB->FileName, fileName, name_len);
4643 }
4644
4645 params = 6 + name_len;
4646 count = sizeof (FILE_BASIC_INFO);
4647 pSMB->MaxParameterCount = cpu_to_le16(2);
4648 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4649 pSMB->MaxSetupCount = 0;
4650 pSMB->Reserved = 0;
4651 pSMB->Flags = 0;
4652 pSMB->Timeout = 0;
4653 pSMB->Reserved2 = 0;
4654 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4655 InformationLevel) - 4;
4656 offset = param_offset + params;
4657 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4658 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4659 pSMB->DataOffset = cpu_to_le16(offset);
4660 pSMB->SetupCount = 1;
4661 pSMB->Reserved3 = 0;
4662 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4663 byte_count = 3 /* pad */ + params + count;
4664
4665 pSMB->DataCount = cpu_to_le16(count);
4666 pSMB->ParameterCount = cpu_to_le16(params);
4667 pSMB->TotalDataCount = pSMB->DataCount;
4668 pSMB->TotalParameterCount = pSMB->ParameterCount;
4669 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4670 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4671 else
4672 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4673 pSMB->Reserved4 = 0;
4674 pSMB->hdr.smb_buf_length += byte_count;
4675 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4676 pSMB->ByteCount = cpu_to_le16(byte_count);
4677 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4678 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4679 if (rc) {
4680 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4681 }
4682
4683 cifs_buf_release(pSMB);
4684
4685 if (rc == -EAGAIN)
4686 goto SetTimesRetry;
4687
4688 return rc;
4689 }
4690
4691 /* Can not be used to set time stamps yet (due to old DOS time format) */
4692 /* Can be used to set attributes */
4693 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4694 handling it anyway and NT4 was what we thought it would be needed for
4695 Do not delete it until we prove whether needed for Win9x though */
4696 int
4697 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4698 __u16 dos_attrs, const struct nls_table *nls_codepage)
4699 {
4700 SETATTR_REQ *pSMB = NULL;
4701 SETATTR_RSP *pSMBr = NULL;
4702 int rc = 0;
4703 int bytes_returned;
4704 int name_len;
4705
4706 cFYI(1, ("In SetAttrLegacy"));
4707
4708 SetAttrLgcyRetry:
4709 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4710 (void **) &pSMBr);
4711 if (rc)
4712 return rc;
4713
4714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4715 name_len =
4716 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4717 PATH_MAX, nls_codepage);
4718 name_len++; /* trailing null */
4719 name_len *= 2;
4720 } else { /* BB improve the check for buffer overruns BB */
4721 name_len = strnlen(fileName, PATH_MAX);
4722 name_len++; /* trailing null */
4723 strncpy(pSMB->fileName, fileName, name_len);
4724 }
4725 pSMB->attr = cpu_to_le16(dos_attrs);
4726 pSMB->BufferFormat = 0x04;
4727 pSMB->hdr.smb_buf_length += name_len + 1;
4728 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4731 if (rc) {
4732 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4733 }
4734
4735 cifs_buf_release(pSMB);
4736
4737 if (rc == -EAGAIN)
4738 goto SetAttrLgcyRetry;
4739
4740 return rc;
4741 }
4742 #endif /* temporarily unneeded SetAttr legacy function */
4743
4744 int
4745 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4746 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4747 dev_t device, const struct nls_table *nls_codepage,
4748 int remap)
4749 {
4750 TRANSACTION2_SPI_REQ *pSMB = NULL;
4751 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4752 int name_len;
4753 int rc = 0;
4754 int bytes_returned = 0;
4755 FILE_UNIX_BASIC_INFO *data_offset;
4756 __u16 params, param_offset, offset, count, byte_count;
4757
4758 cFYI(1, ("In SetUID/GID/Mode"));
4759 setPermsRetry:
4760 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4761 (void **) &pSMBr);
4762 if (rc)
4763 return rc;
4764
4765 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4766 name_len =
4767 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4768 PATH_MAX, nls_codepage, remap);
4769 name_len++; /* trailing null */
4770 name_len *= 2;
4771 } else { /* BB improve the check for buffer overruns BB */
4772 name_len = strnlen(fileName, PATH_MAX);
4773 name_len++; /* trailing null */
4774 strncpy(pSMB->FileName, fileName, name_len);
4775 }
4776
4777 params = 6 + name_len;
4778 count = sizeof (FILE_UNIX_BASIC_INFO);
4779 pSMB->MaxParameterCount = cpu_to_le16(2);
4780 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4781 pSMB->MaxSetupCount = 0;
4782 pSMB->Reserved = 0;
4783 pSMB->Flags = 0;
4784 pSMB->Timeout = 0;
4785 pSMB->Reserved2 = 0;
4786 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4787 InformationLevel) - 4;
4788 offset = param_offset + params;
4789 data_offset =
4790 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4791 offset);
4792 memset(data_offset, 0, count);
4793 pSMB->DataOffset = cpu_to_le16(offset);
4794 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4795 pSMB->SetupCount = 1;
4796 pSMB->Reserved3 = 0;
4797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4798 byte_count = 3 /* pad */ + params + count;
4799 pSMB->ParameterCount = cpu_to_le16(params);
4800 pSMB->DataCount = cpu_to_le16(count);
4801 pSMB->TotalParameterCount = pSMB->ParameterCount;
4802 pSMB->TotalDataCount = pSMB->DataCount;
4803 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4804 pSMB->Reserved4 = 0;
4805 pSMB->hdr.smb_buf_length += byte_count;
4806 data_offset->Uid = cpu_to_le64(uid);
4807 data_offset->Gid = cpu_to_le64(gid);
4808 /* better to leave device as zero when it is */
4809 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4810 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4811 data_offset->Permissions = cpu_to_le64(mode);
4812
4813 if(S_ISREG(mode))
4814 data_offset->Type = cpu_to_le32(UNIX_FILE);
4815 else if(S_ISDIR(mode))
4816 data_offset->Type = cpu_to_le32(UNIX_DIR);
4817 else if(S_ISLNK(mode))
4818 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4819 else if(S_ISCHR(mode))
4820 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4821 else if(S_ISBLK(mode))
4822 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4823 else if(S_ISFIFO(mode))
4824 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4825 else if(S_ISSOCK(mode))
4826 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4827
4828
4829 pSMB->ByteCount = cpu_to_le16(byte_count);
4830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4832 if (rc) {
4833 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4834 }
4835
4836 if (pSMB)
4837 cifs_buf_release(pSMB);
4838 if (rc == -EAGAIN)
4839 goto setPermsRetry;
4840 return rc;
4841 }
4842
4843 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4844 const int notify_subdirs, const __u16 netfid,
4845 __u32 filter, struct file * pfile, int multishot,
4846 const struct nls_table *nls_codepage)
4847 {
4848 int rc = 0;
4849 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4850 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4851 struct dir_notify_req *dnotify_req;
4852 int bytes_returned;
4853
4854 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4855 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4856 (void **) &pSMBr);
4857 if (rc)
4858 return rc;
4859
4860 pSMB->TotalParameterCount = 0 ;
4861 pSMB->TotalDataCount = 0;
4862 pSMB->MaxParameterCount = cpu_to_le32(2);
4863 /* BB find exact data count max from sess structure BB */
4864 pSMB->MaxDataCount = 0; /* same in little endian or be */
4865 /* BB VERIFY verify which is correct for above BB */
4866 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4867 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4868
4869 pSMB->MaxSetupCount = 4;
4870 pSMB->Reserved = 0;
4871 pSMB->ParameterOffset = 0;
4872 pSMB->DataCount = 0;
4873 pSMB->DataOffset = 0;
4874 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4875 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4876 pSMB->ParameterCount = pSMB->TotalParameterCount;
4877 if(notify_subdirs)
4878 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4879 pSMB->Reserved2 = 0;
4880 pSMB->CompletionFilter = cpu_to_le32(filter);
4881 pSMB->Fid = netfid; /* file handle always le */
4882 pSMB->ByteCount = 0;
4883
4884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4885 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4886 if (rc) {
4887 cFYI(1, ("Error in Notify = %d", rc));
4888 } else {
4889 /* Add file to outstanding requests */
4890 /* BB change to kmem cache alloc */
4891 dnotify_req = kmalloc(
4892 sizeof(struct dir_notify_req),
4893 GFP_KERNEL);
4894 if(dnotify_req) {
4895 dnotify_req->Pid = pSMB->hdr.Pid;
4896 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4897 dnotify_req->Mid = pSMB->hdr.Mid;
4898 dnotify_req->Tid = pSMB->hdr.Tid;
4899 dnotify_req->Uid = pSMB->hdr.Uid;
4900 dnotify_req->netfid = netfid;
4901 dnotify_req->pfile = pfile;
4902 dnotify_req->filter = filter;
4903 dnotify_req->multishot = multishot;
4904 spin_lock(&GlobalMid_Lock);
4905 list_add_tail(&dnotify_req->lhead,
4906 &GlobalDnotifyReqList);
4907 spin_unlock(&GlobalMid_Lock);
4908 } else
4909 rc = -ENOMEM;
4910 }
4911 cifs_buf_release(pSMB);
4912 return rc;
4913 }
4914 #ifdef CONFIG_CIFS_XATTR
4915 ssize_t
4916 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4917 const unsigned char *searchName,
4918 char * EAData, size_t buf_size,
4919 const struct nls_table *nls_codepage, int remap)
4920 {
4921 /* BB assumes one setup word */
4922 TRANSACTION2_QPI_REQ *pSMB = NULL;
4923 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4924 int rc = 0;
4925 int bytes_returned;
4926 int name_len;
4927 struct fea * temp_fea;
4928 char * temp_ptr;
4929 __u16 params, byte_count;
4930
4931 cFYI(1, ("In Query All EAs path %s", searchName));
4932 QAllEAsRetry:
4933 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4934 (void **) &pSMBr);
4935 if (rc)
4936 return rc;
4937
4938 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4939 name_len =
4940 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4941 PATH_MAX, nls_codepage, remap);
4942 name_len++; /* trailing null */
4943 name_len *= 2;
4944 } else { /* BB improve the check for buffer overruns BB */
4945 name_len = strnlen(searchName, PATH_MAX);
4946 name_len++; /* trailing null */
4947 strncpy(pSMB->FileName, searchName, name_len);
4948 }
4949
4950 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4951 pSMB->TotalDataCount = 0;
4952 pSMB->MaxParameterCount = cpu_to_le16(2);
4953 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4954 pSMB->MaxSetupCount = 0;
4955 pSMB->Reserved = 0;
4956 pSMB->Flags = 0;
4957 pSMB->Timeout = 0;
4958 pSMB->Reserved2 = 0;
4959 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4960 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4961 pSMB->DataCount = 0;
4962 pSMB->DataOffset = 0;
4963 pSMB->SetupCount = 1;
4964 pSMB->Reserved3 = 0;
4965 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4966 byte_count = params + 1 /* pad */ ;
4967 pSMB->TotalParameterCount = cpu_to_le16(params);
4968 pSMB->ParameterCount = pSMB->TotalParameterCount;
4969 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4970 pSMB->Reserved4 = 0;
4971 pSMB->hdr.smb_buf_length += byte_count;
4972 pSMB->ByteCount = cpu_to_le16(byte_count);
4973
4974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4976 if (rc) {
4977 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4978 } else { /* decode response */
4979 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4980
4981 /* BB also check enough total bytes returned */
4982 /* BB we need to improve the validity checking
4983 of these trans2 responses */
4984 if (rc || (pSMBr->ByteCount < 4))
4985 rc = -EIO; /* bad smb */
4986 /* else if (pFindData){
4987 memcpy((char *) pFindData,
4988 (char *) &pSMBr->hdr.Protocol +
4989 data_offset, kl);
4990 }*/ else {
4991 /* check that length of list is not more than bcc */
4992 /* check that each entry does not go beyond length
4993 of list */
4994 /* check that each element of each entry does not
4995 go beyond end of list */
4996 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4997 struct fealist * ea_response_data;
4998 rc = 0;
4999 /* validate_trans2_offsets() */
5000 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5001 ea_response_data = (struct fealist *)
5002 (((char *) &pSMBr->hdr.Protocol) +
5003 data_offset);
5004 name_len = le32_to_cpu(ea_response_data->list_len);
5005 cFYI(1,("ea length %d", name_len));
5006 if(name_len <= 8) {
5007 /* returned EA size zeroed at top of function */
5008 cFYI(1,("empty EA list returned from server"));
5009 } else {
5010 /* account for ea list len */
5011 name_len -= 4;
5012 temp_fea = ea_response_data->list;
5013 temp_ptr = (char *)temp_fea;
5014 while(name_len > 0) {
5015 __u16 value_len;
5016 name_len -= 4;
5017 temp_ptr += 4;
5018 rc += temp_fea->name_len;
5019 /* account for prefix user. and trailing null */
5020 rc = rc + 5 + 1;
5021 if(rc<(int)buf_size) {
5022 memcpy(EAData,"user.",5);
5023 EAData+=5;
5024 memcpy(EAData,temp_ptr,temp_fea->name_len);
5025 EAData+=temp_fea->name_len;
5026 /* null terminate name */
5027 *EAData = 0;
5028 EAData = EAData + 1;
5029 } else if(buf_size == 0) {
5030 /* skip copy - calc size only */
5031 } else {
5032 /* stop before overrun buffer */
5033 rc = -ERANGE;
5034 break;
5035 }
5036 name_len -= temp_fea->name_len;
5037 temp_ptr += temp_fea->name_len;
5038 /* account for trailing null */
5039 name_len--;
5040 temp_ptr++;
5041 value_len = le16_to_cpu(temp_fea->value_len);
5042 name_len -= value_len;
5043 temp_ptr += value_len;
5044 /* BB check that temp_ptr is still within smb BB*/
5045 /* no trailing null to account for in value len */
5046 /* go on to next EA */
5047 temp_fea = (struct fea *)temp_ptr;
5048 }
5049 }
5050 }
5051 }
5052 if (pSMB)
5053 cifs_buf_release(pSMB);
5054 if (rc == -EAGAIN)
5055 goto QAllEAsRetry;
5056
5057 return (ssize_t)rc;
5058 }
5059
5060 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5061 const unsigned char * searchName,const unsigned char * ea_name,
5062 unsigned char * ea_value, size_t buf_size,
5063 const struct nls_table *nls_codepage, int remap)
5064 {
5065 TRANSACTION2_QPI_REQ *pSMB = NULL;
5066 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5067 int rc = 0;
5068 int bytes_returned;
5069 int name_len;
5070 struct fea * temp_fea;
5071 char * temp_ptr;
5072 __u16 params, byte_count;
5073
5074 cFYI(1, ("In Query EA path %s", searchName));
5075 QEARetry:
5076 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5077 (void **) &pSMBr);
5078 if (rc)
5079 return rc;
5080
5081 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5082 name_len =
5083 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5084 PATH_MAX, nls_codepage, remap);
5085 name_len++; /* trailing null */
5086 name_len *= 2;
5087 } else { /* BB improve the check for buffer overruns BB */
5088 name_len = strnlen(searchName, PATH_MAX);
5089 name_len++; /* trailing null */
5090 strncpy(pSMB->FileName, searchName, name_len);
5091 }
5092
5093 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5094 pSMB->TotalDataCount = 0;
5095 pSMB->MaxParameterCount = cpu_to_le16(2);
5096 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5097 pSMB->MaxSetupCount = 0;
5098 pSMB->Reserved = 0;
5099 pSMB->Flags = 0;
5100 pSMB->Timeout = 0;
5101 pSMB->Reserved2 = 0;
5102 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5103 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5104 pSMB->DataCount = 0;
5105 pSMB->DataOffset = 0;
5106 pSMB->SetupCount = 1;
5107 pSMB->Reserved3 = 0;
5108 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5109 byte_count = params + 1 /* pad */ ;
5110 pSMB->TotalParameterCount = cpu_to_le16(params);
5111 pSMB->ParameterCount = pSMB->TotalParameterCount;
5112 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5113 pSMB->Reserved4 = 0;
5114 pSMB->hdr.smb_buf_length += byte_count;
5115 pSMB->ByteCount = cpu_to_le16(byte_count);
5116
5117 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5119 if (rc) {
5120 cFYI(1, ("Send error in Query EA = %d", rc));
5121 } else { /* decode response */
5122 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5123
5124 /* BB also check enough total bytes returned */
5125 /* BB we need to improve the validity checking
5126 of these trans2 responses */
5127 if (rc || (pSMBr->ByteCount < 4))
5128 rc = -EIO; /* bad smb */
5129 /* else if (pFindData){
5130 memcpy((char *) pFindData,
5131 (char *) &pSMBr->hdr.Protocol +
5132 data_offset, kl);
5133 }*/ else {
5134 /* check that length of list is not more than bcc */
5135 /* check that each entry does not go beyond length
5136 of list */
5137 /* check that each element of each entry does not
5138 go beyond end of list */
5139 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5140 struct fealist * ea_response_data;
5141 rc = -ENODATA;
5142 /* validate_trans2_offsets() */
5143 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5144 ea_response_data = (struct fealist *)
5145 (((char *) &pSMBr->hdr.Protocol) +
5146 data_offset);
5147 name_len = le32_to_cpu(ea_response_data->list_len);
5148 cFYI(1,("ea length %d", name_len));
5149 if(name_len <= 8) {
5150 /* returned EA size zeroed at top of function */
5151 cFYI(1,("empty EA list returned from server"));
5152 } else {
5153 /* account for ea list len */
5154 name_len -= 4;
5155 temp_fea = ea_response_data->list;
5156 temp_ptr = (char *)temp_fea;
5157 /* loop through checking if we have a matching
5158 name and then return the associated value */
5159 while(name_len > 0) {
5160 __u16 value_len;
5161 name_len -= 4;
5162 temp_ptr += 4;
5163 value_len = le16_to_cpu(temp_fea->value_len);
5164 /* BB validate that value_len falls within SMB,
5165 even though maximum for name_len is 255 */
5166 if(memcmp(temp_fea->name,ea_name,
5167 temp_fea->name_len) == 0) {
5168 /* found a match */
5169 rc = value_len;
5170 /* account for prefix user. and trailing null */
5171 if(rc<=(int)buf_size) {
5172 memcpy(ea_value,
5173 temp_fea->name+temp_fea->name_len+1,
5174 rc);
5175 /* ea values, unlike ea names,
5176 are not null terminated */
5177 } else if(buf_size == 0) {
5178 /* skip copy - calc size only */
5179 } else {
5180 /* stop before overrun buffer */
5181 rc = -ERANGE;
5182 }
5183 break;
5184 }
5185 name_len -= temp_fea->name_len;
5186 temp_ptr += temp_fea->name_len;
5187 /* account for trailing null */
5188 name_len--;
5189 temp_ptr++;
5190 name_len -= value_len;
5191 temp_ptr += value_len;
5192 /* no trailing null to account for in value len */
5193 /* go on to next EA */
5194 temp_fea = (struct fea *)temp_ptr;
5195 }
5196 }
5197 }
5198 }
5199 if (pSMB)
5200 cifs_buf_release(pSMB);
5201 if (rc == -EAGAIN)
5202 goto QEARetry;
5203
5204 return (ssize_t)rc;
5205 }
5206
5207 int
5208 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5209 const char * ea_name, const void * ea_value,
5210 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5211 int remap)
5212 {
5213 struct smb_com_transaction2_spi_req *pSMB = NULL;
5214 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5215 struct fealist *parm_data;
5216 int name_len;
5217 int rc = 0;
5218 int bytes_returned = 0;
5219 __u16 params, param_offset, byte_count, offset, count;
5220
5221 cFYI(1, ("In SetEA"));
5222 SetEARetry:
5223 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5224 (void **) &pSMBr);
5225 if (rc)
5226 return rc;
5227
5228 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5229 name_len =
5230 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5231 PATH_MAX, nls_codepage, remap);
5232 name_len++; /* trailing null */
5233 name_len *= 2;
5234 } else { /* BB improve the check for buffer overruns BB */
5235 name_len = strnlen(fileName, PATH_MAX);
5236 name_len++; /* trailing null */
5237 strncpy(pSMB->FileName, fileName, name_len);
5238 }
5239
5240 params = 6 + name_len;
5241
5242 /* done calculating parms using name_len of file name,
5243 now use name_len to calculate length of ea name
5244 we are going to create in the inode xattrs */
5245 if(ea_name == NULL)
5246 name_len = 0;
5247 else
5248 name_len = strnlen(ea_name,255);
5249
5250 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5251 pSMB->MaxParameterCount = cpu_to_le16(2);
5252 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5253 pSMB->MaxSetupCount = 0;
5254 pSMB->Reserved = 0;
5255 pSMB->Flags = 0;
5256 pSMB->Timeout = 0;
5257 pSMB->Reserved2 = 0;
5258 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5259 InformationLevel) - 4;
5260 offset = param_offset + params;
5261 pSMB->InformationLevel =
5262 cpu_to_le16(SMB_SET_FILE_EA);
5263
5264 parm_data =
5265 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5266 offset);
5267 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5268 pSMB->DataOffset = cpu_to_le16(offset);
5269 pSMB->SetupCount = 1;
5270 pSMB->Reserved3 = 0;
5271 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5272 byte_count = 3 /* pad */ + params + count;
5273 pSMB->DataCount = cpu_to_le16(count);
5274 parm_data->list_len = cpu_to_le32(count);
5275 parm_data->list[0].EA_flags = 0;
5276 /* we checked above that name len is less than 255 */
5277 parm_data->list[0].name_len = (__u8)name_len;
5278 /* EA names are always ASCII */
5279 if(ea_name)
5280 strncpy(parm_data->list[0].name,ea_name,name_len);
5281 parm_data->list[0].name[name_len] = 0;
5282 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5283 /* caller ensures that ea_value_len is less than 64K but
5284 we need to ensure that it fits within the smb */
5285
5286 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5287 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5288 if(ea_value_len)
5289 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5290
5291 pSMB->TotalDataCount = pSMB->DataCount;
5292 pSMB->ParameterCount = cpu_to_le16(params);
5293 pSMB->TotalParameterCount = pSMB->ParameterCount;
5294 pSMB->Reserved4 = 0;
5295 pSMB->hdr.smb_buf_length += byte_count;
5296 pSMB->ByteCount = cpu_to_le16(byte_count);
5297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5299 if (rc) {
5300 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5301 }
5302
5303 cifs_buf_release(pSMB);
5304
5305 if (rc == -EAGAIN)
5306 goto SetEARetry;
5307
5308 return rc;
5309 }
5310
5311 #endif
This page took 0.14355 seconds and 5 git commands to generate.