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