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