aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifssmb.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r--fs/cifs/cifssmb.c179
1 files changed, 176 insertions, 3 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 1620991cd4d2..20300bc9ae77 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1926,6 +1926,90 @@ querySymLinkRetry:
1926 return rc; 1926 return rc;
1927} 1927}
1928 1928
1929/* Initialize NT TRANSACT SMB into small smb request buffer.
1930 This assumes that all NT TRANSACTS that we init here have
1931 total parm and data under about 400 bytes (to fit in small cifs
1932 buffer size), which is the case so far, it easily fits. NB:
1933 Setup words themselves and ByteCount
1934 MaxSetupCount (size of returned setup area) and
1935 MaxParameterCount (returned parms size) must be set by caller */
1936static int
1937smb_init_ntransact(const __u16 sub_command, const int setup_count,
1938 const int parm_len, struct cifsTconInfo *tcon,
1939 void ** ret_buf)
1940{
1941 int rc;
1942 __u32 temp_offset;
1943 struct smb_com_ntransact_req * pSMB;
1944
1945 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1946 (void **)&pSMB);
1947 if (rc)
1948 return rc;
1949 *ret_buf = (void *)pSMB;
1950 pSMB->Reserved = 0;
1951 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1952 pSMB->TotalDataCount = 0;
1953 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1954 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1955 pSMB->ParameterCount = pSMB->TotalParameterCount;
1956 pSMB->DataCount = pSMB->TotalDataCount;
1957 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1958 (setup_count * 2) - 4 /* for rfc1001 length itself */;
1959 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1960 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1961 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1962 pSMB->SubCommand = cpu_to_le16(sub_command);
1963 return 0;
1964}
1965
1966static int
1967validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1968 int * pdatalen, int * pparmlen)
1969{
1970 char * end_of_smb;
1971 __u32 data_count, data_offset, parm_count, parm_offset;
1972 struct smb_com_ntransact_rsp * pSMBr;
1973
1974 if(buf == NULL)
1975 return -EINVAL;
1976
1977 pSMBr = (struct smb_com_ntransact_rsp *)buf;
1978
1979 /* ByteCount was converted from little endian in SendReceive */
1980 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
1981 (char *)&pSMBr->ByteCount;
1982
1983
1984 data_offset = le32_to_cpu(pSMBr->DataOffset);
1985 data_count = le32_to_cpu(pSMBr->DataCount);
1986 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
1987 parm_count = le32_to_cpu(pSMBr->ParameterCount);
1988
1989 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
1990 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
1991
1992 /* should we also check that parm and data areas do not overlap? */
1993 if(*ppparm > end_of_smb) {
1994 cFYI(1,("parms start after end of smb"));
1995 return -EINVAL;
1996 } else if(parm_count + *ppparm > end_of_smb) {
1997 cFYI(1,("parm end after end of smb"));
1998 return -EINVAL;
1999 } else if(*ppdata > end_of_smb) {
2000 cFYI(1,("data starts after end of smb"));
2001 return -EINVAL;
2002 } else if(data_count + *ppdata > end_of_smb) {
2003 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2004 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2005 return -EINVAL;
2006 } else if(parm_count + data_count > pSMBr->ByteCount) {
2007 cFYI(1,("parm count and data count larger than SMB"));
2008 return -EINVAL;
2009 }
2010 return 0;
2011}
2012
1929int 2013int
1930CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, 2014CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1931 const unsigned char *searchName, 2015 const unsigned char *searchName,
@@ -1948,7 +2032,8 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1948 pSMB->TotalDataCount = 0; 2032 pSMB->TotalDataCount = 0;
1949 pSMB->MaxParameterCount = cpu_to_le32(2); 2033 pSMB->MaxParameterCount = cpu_to_le32(2);
1950 /* BB find exact data count max from sess structure BB */ 2034 /* BB find exact data count max from sess structure BB */
1951 pSMB->MaxDataCount = cpu_to_le32(4000); 2035 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2036 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1952 pSMB->MaxSetupCount = 4; 2037 pSMB->MaxSetupCount = 4;
1953 pSMB->Reserved = 0; 2038 pSMB->Reserved = 0;
1954 pSMB->ParameterOffset = 0; 2039 pSMB->ParameterOffset = 0;
@@ -1975,7 +2060,9 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1975 rc = -EIO; /* bad smb */ 2060 rc = -EIO; /* bad smb */
1976 else { 2061 else {
1977 if(data_count && (data_count < 2048)) { 2062 if(data_count && (data_count < 2048)) {
1978 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount; 2063 char * end_of_smb = 2 /* sizeof byte count */ +
2064 pSMBr->ByteCount +
2065 (char *)&pSMBr->ByteCount;
1979 2066
1980 struct reparse_data * reparse_buf = (struct reparse_data *) 2067 struct reparse_data * reparse_buf = (struct reparse_data *)
1981 ((char *)&pSMBr->hdr.Protocol + data_offset); 2068 ((char *)&pSMBr->hdr.Protocol + data_offset);
@@ -2219,6 +2306,7 @@ queryAclRetry:
2219 2306
2220 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 2307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2221 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 2308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2309 cifs_stats_inc(&tcon->num_acl_get);
2222 if (rc) { 2310 if (rc) {
2223 cFYI(1, ("Send error in Query POSIX ACL = %d", rc)); 2311 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2224 } else { 2312 } else {
@@ -2406,6 +2494,87 @@ GetExtAttrOut:
2406 2494
2407#endif /* CONFIG_POSIX */ 2495#endif /* CONFIG_POSIX */
2408 2496
2497/* Convert CIFS ACL to POSIX form */
2498static int parse_sec_desc(struct sec_desc * psec_desc, int acl_len)
2499{
2500 CHECK ON OTHER COMPUTER TO SEE IF FORMAT ENCODED IN CIFSPDU.H ALREADY
2501 return 0;
2502}
2503
2504/* Get Security Descriptor (by handle) from remote server for a file or dir */
2505int
2506CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2507 /* BB fix up return info */ char *acl_inf, const int buflen,
2508 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2509{
2510 int rc = 0;
2511 int buf_type = 0;
2512 QUERY_SEC_DESC_REQ * pSMB;
2513 struct kvec iov[1];
2514
2515 cFYI(1, ("GetCifsACL"));
2516
2517 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2518 8 /* parm len */, tcon, (void **) &pSMB);
2519 if (rc)
2520 return rc;
2521
2522 pSMB->MaxParameterCount = cpu_to_le32(4);
2523 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2524 pSMB->MaxSetupCount = 0;
2525 pSMB->Fid = fid; /* file handle always le */
2526 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2527 CIFS_ACL_DACL);
2528 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2529 pSMB->hdr.smb_buf_length += 11;
2530 iov[0].iov_base = (char *)pSMB;
2531 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2532
2533 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2534 cifs_stats_inc(&tcon->num_acl_get);
2535 if (rc) {
2536 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2537 } else { /* decode response */
2538 struct sec_desc * psec_desc;
2539 __le32 * parm;
2540 int parm_len;
2541 int data_len;
2542 int acl_len;
2543 struct smb_com_ntransact_rsp * pSMBr;
2544
2545/* validate_nttransact */
2546 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2547 (char **)&psec_desc,
2548 &parm_len, &data_len);
2549
2550 if(rc)
2551 goto qsec_out;
2552 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2553
2554 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2555
2556 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2557 rc = -EIO; /* bad smb */
2558 goto qsec_out;
2559 }
2560
2561/* BB check that data area is minimum length and as big as acl_len */
2562
2563 acl_len = le32_to_cpu(*(__le32 *)parm);
2564 /* BB check if(acl_len > bufsize) */
2565
2566 parse_sec_desc(psec_desc, acl_len);
2567 }
2568qsec_out:
2569 if(buf_type == CIFS_SMALL_BUFFER)
2570 cifs_small_buf_release(iov[0].iov_base);
2571 else if(buf_type == CIFS_LARGE_BUFFER)
2572 cifs_buf_release(iov[0].iov_base);
2573 cifs_small_buf_release(pSMB);
2574 return rc;
2575}
2576
2577
2409/* Legacy Query Path Information call for lookup to old servers such 2578/* Legacy Query Path Information call for lookup to old servers such
2410 as Win9x/WinME */ 2579 as Win9x/WinME */
2411int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, 2580int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
@@ -4304,7 +4473,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4304{ 4473{
4305 int rc = 0; 4474 int rc = 0;
4306 struct smb_com_transaction_change_notify_req * pSMB = NULL; 4475 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4307 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; 4476 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4308 struct dir_notify_req *dnotify_req; 4477 struct dir_notify_req *dnotify_req;
4309 int bytes_returned; 4478 int bytes_returned;
4310 4479
@@ -4319,6 +4488,10 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4319 pSMB->MaxParameterCount = cpu_to_le32(2); 4488 pSMB->MaxParameterCount = cpu_to_le32(2);
4320 /* BB find exact data count max from sess structure BB */ 4489 /* BB find exact data count max from sess structure BB */
4321 pSMB->MaxDataCount = 0; /* same in little endian or be */ 4490 pSMB->MaxDataCount = 0; /* same in little endian or be */
4491/* BB VERIFY verify which is correct for above BB */
4492 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4493 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4494
4322 pSMB->MaxSetupCount = 4; 4495 pSMB->MaxSetupCount = 4;
4323 pSMB->Reserved = 0; 4496 pSMB->Reserved = 0;
4324 pSMB->ParameterOffset = 0; 4497 pSMB->ParameterOffset = 0;