Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (24 commits)
  [CIFS] merge conflict in fs/cifs/export.c
  [CIFS] Allow disabling CIFS Unix Extensions as mount option
  [CIFS] More whitespace/formatting fixes (noticed by checkpatch)
  [CIFS] Typo in previous patch
  [CIFS] zero_user_page() conversions
  [CIFS] use simple_prepare_write to zero page data
  [CIFS] Fix build break - inet.h not included when experimental ifdef off
  [CIFS] Add support for new POSIX unlink
  [CIFS] whitespace/formatting fixes
  [CIFS] Fix oops in cifs_create when nfsd server exports cifs mount
  [CIFS] whitespace cleanup
  [CIFS] Fix packet signatures for NTLMv2 case
  [CIFS] more whitespace fixes
  [CIFS] more whitespace cleanup
  [CIFS] whitespace cleanup
  [CIFS] whitespace cleanup
  [CIFS] ipv6 support no longer experimental
  [CIFS] Mount should fail if server signing off but client mount option requires it
  [CIFS] whitespace fixes
  [CIFS] Fix sign mount option and sign proc config setting
  ...
This commit is contained in:
Linus Torvalds 2007-07-18 18:32:28 -07:00
commit 789c56b7f7
38 changed files with 3435 additions and 3151 deletions

View file

@ -1,3 +1,10 @@
Version 1.50
------------
Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is
done with "serverino" mount option). Add support for POSIX Unlink
(helps with certain sharing violation cases when server such as
Samba supports newer POSIX CIFS Protocol Extensions).
Version 1.49 Version 1.49
------------ ------------
IPv6 support. Enable ipv6 addresses to be passed on mount (put the ipv6 IPv6 support. Enable ipv6 addresses to be passed on mount (put the ipv6
@ -8,7 +15,11 @@ when Unix Extensions were ignored). This allows users to override the
default uid and gid for files when they are certain that the uids or default uid and gid for files when they are certain that the uids or
gids on the server do not match those of the client. Make "sec=none" gids on the server do not match those of the client. Make "sec=none"
mount override username (so that null user connection is attempted) mount override username (so that null user connection is attempted)
to match what documentation said. to match what documentation said. Support for very large reads, over 127K,
available to some newer servers (such as Samba 3.0.26 and later but
note that it also requires setting CIFSMaxBufSize at module install
time to a larger value which may hurt performance in some cases).
Make sign option force signing (or fail if server does not support it).
Version 1.48 Version 1.48
------------ ------------

View file

@ -301,10 +301,21 @@ A partial list of the supported mount options follows:
during the local client kernel build will be used. during the local client kernel build will be used.
If server does not support Unicode, this parameter is If server does not support Unicode, this parameter is
unused. unused.
rsize default read size (usually 16K) rsize default read size (usually 16K). The client currently
wsize default write size (usually 16K, 32K is often better over GigE) can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize
maximum wsize currently allowed by CIFS is 57344 (14 4096 byte defaults to 16K and may be changed (from 8K to the maximum
pages) kmalloc size allowed by your kernel) at module install time
for cifs.ko. Setting CIFSMaxBufSize to a very large value
will cause cifs to use more memory and may reduce performance
in some cases. To use rsize greater than 127K (the original
cifs protocol maximum) also requires that the server support
a new Unix Capability flag (for very large read) which some
newer servers (e.g. Samba 3.0.26 or later) do. rsize can be
set from a minimum of 2048 to a maximum of 130048 (127K or
CIFSMaxBufSize, whichever is smaller)
wsize default write size (default 57344)
maximum wsize currently allowed by CIFS is 57344 (fourteen
4096 byte pages)
rw mount the network share read-write (note that the rw mount the network share read-write (note that the
server may still consider the share read-only) server may still consider the share read-only)
ro mount network share read-only ro mount network share read-only
@ -359,7 +370,7 @@ A partial list of the supported mount options follows:
Note that this does not affect the normal ACL check on the Note that this does not affect the normal ACL check on the
target machine done by the server software (of the server target machine done by the server software (of the server
ACL against the user name provided at mount time). ACL against the user name provided at mount time).
serverino Use servers inode numbers instead of generating automatically serverino Use server's inode numbers instead of generating automatically
incrementing inode numbers on the client. Although this will incrementing inode numbers on the client. Although this will
make it easier to spot hardlinked files (as they will have make it easier to spot hardlinked files (as they will have
the same inode numbers) and inode numbers may be persistent, the same inode numbers) and inode numbers may be persistent,
@ -367,12 +378,11 @@ A partial list of the supported mount options follows:
are unique if multiple server side mounts are exported under a are unique if multiple server side mounts are exported under a
single share (since inode numbers on the servers might not single share (since inode numbers on the servers might not
be unique if multiple filesystems are mounted under the same be unique if multiple filesystems are mounted under the same
shared higher level directory). Note that this requires that shared higher level directory). Note that some older
the server support the CIFS Unix Extensions as other servers (e.g. pre-Windows 2000) do not support returning UniqueIDs
do not return a unique IndexNumber on SMB FindFirst (most or the CIFS Unix Extensions equivalent and for those
servers return zero as the IndexNumber). Parameter has no this mount option will have no effect. Exporting cifs mounts
effect to Windows servers and others which do not support the under nfsd requires this mount option on the cifs mount.
CIFS Unix Extensions.
noserverino Client generates inode numbers (rather than using the actual one noserverino Client generates inode numbers (rather than using the actual one
from the server) by default. from the server) by default.
setuids If the CIFS Unix extensions are negotiated with the server setuids If the CIFS Unix extensions are negotiated with the server
@ -582,10 +592,10 @@ the start of smb requests and responses can be enabled via:
echo 1 > /proc/fs/cifs/traceSMB echo 1 > /proc/fs/cifs/traceSMB
Two other experimental features are under development and to test Two other experimental features are under development. To test these
require enabling CONFIG_CIFS_EXPERIMENTAL requires enabling CONFIG_CIFS_EXPERIMENTAL
More efficient write operations ipv6 enablement
DNOTIFY fcntl: needed for support of directory change DNOTIFY fcntl: needed for support of directory change
notification and perhaps later for file leases) notification and perhaps later for file leases)

View file

@ -18,9 +18,9 @@ better)
d) Kerberos/SPNEGO session setup support - (started) d) Kerberos/SPNEGO session setup support - (started)
e) More testing of NTLMv2 authentication (mostly implemented - double check e) Cleanup now unneeded SessSetup code in
that NTLMv2 signing works, also need to cleanup now unneeded SessSetup code in fs/cifs/connect.c and add back in NTLMSSP code if any servers
fs/cifs/connect.c) need it
f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup
used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
@ -106,6 +106,12 @@ but recognizes them
succeed but still return access denied (appears to be Windows succeed but still return access denied (appears to be Windows
server not cifs client problem) and has not been reproduced recently. server not cifs client problem) and has not been reproduced recently.
NTFS partitions do not have this problem. NTFS partitions do not have this problem.
4) Unix/POSIX capabilities are reset after reconnection, and affect
a few fields in the tree connection but we do do not know which
superblocks to apply these changes to. We should probably walk
the list of superblocks to set these. Also need to check the
flags on the second mount to the same share, and see if we
can do the same trick that NFS does to remount duplicate shares.
Misc testing to do Misc testing to do
================== ==================

View file

@ -498,7 +498,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
return 0; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON) } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|| (tag != ASN1_EOC)) { || (tag != ASN1_EOC)) {
cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0", cFYI(1,
("cls = %d con = %d tag = %d end = %p (%d) exit 0",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
return 0; return 0;
} }
@ -508,7 +509,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
return 0; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) { || (tag != ASN1_SEQ)) {
cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1", cFYI(1,
("cls = %d con = %d tag = %d end = %p (%d) exit 1",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
return 0; return 0;
} }
@ -540,32 +542,34 @@ decode_negTokenInit(unsigned char *security_blob, int length,
rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
if (!rc) { if (!rc) {
cFYI(1, cFYI(1,
("Error 1 decoding negTokenInit header exit 2")); ("Error decoding negTokenInit hdr exit2"));
return 0; return 0;
} }
if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
if (rc) { if (rc) {
cFYI(1, cFYI(1,
("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx", ("OID len = %d oid = 0x%lx 0x%lx "
oidlen, *oid, *(oid + 1), *(oid + 2), "0x%lx 0x%lx",
*(oid + 3))); oidlen, *oid, *(oid + 1),
rc = compare_oid(oid, oidlen, NTLMSSP_OID, *(oid + 2), *(oid + 3)));
NTLMSSP_OID_LEN); rc = compare_oid(oid, oidlen,
NTLMSSP_OID, NTLMSSP_OID_LEN);
kfree(oid); kfree(oid);
if (rc) if (rc)
use_ntlmssp = TRUE; use_ntlmssp = TRUE;
} }
} else { } else {
cFYI(1,("This should be an oid what is going on? ")); cFYI(1, ("Should be an oid what is going on?"));
} }
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1,
("Error decoding last part of negTokenInit exit 3")); ("Error decoding last part negTokenInit exit3"));
return 0; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
/* tag = 3 indicating mechListMIC */
cFYI(1, cFYI(1,
("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
@ -573,7 +577,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1,
("Error decoding last part of negTokenInit exit 5")); ("Error decoding last part negTokenInit exit5"));
return 0; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) { || (tag != ASN1_SEQ)) {
@ -584,7 +588,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1,
("Error decoding last part of negTokenInit exit 7")); ("Error decoding last part negTokenInit exit 7"));
return 0; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
cFYI(1, cFYI(1,
@ -594,7 +598,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1,
("Error decoding last part of negTokenInit exit 9")); ("Error decoding last part negTokenInit exit9"));
return 0; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_PRI) } else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
|| (tag != ASN1_GENSTR)) { || (tag != ASN1_GENSTR)) {
@ -603,7 +607,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
cls, con, tag, end, *end)); cls, con, tag, end, *end));
return 0; return 0;
} }
cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */ cFYI(1, ("Need to call asn1_octets_decode() function for %s",
ctx.pointer)); /* is this UTF-8 or ASCII? */
} }
/* if (use_kerberos) /* if (use_kerberos)

View file

@ -145,7 +145,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
(ses->serverNOS == NULL)) { (ses->serverNOS == NULL)) {
buf += sprintf(buf, "\nentry for %s not fully " buf += sprintf(buf, "\nentry for %s not fully "
"displayed\n\t", ses->serverName); "displayed\n\t", ses->serverName);
} else { } else {
length = length =
sprintf(buf, sprintf(buf,
@ -901,90 +900,14 @@ security_flags_write(struct file *file, const char __user *buffer,
} }
/* flags look ok - update the global security flags for cifs module */ /* flags look ok - update the global security flags for cifs module */
extended_security = flags; extended_security = flags;
if (extended_security & CIFSSEC_MUST_SIGN) {
/* requiring signing implies signing is allowed */
extended_security |= CIFSSEC_MAY_SIGN;
cFYI(1, ("packet signing now required"));
} else if ((extended_security & CIFSSEC_MAY_SIGN) == 0) {
cFYI(1, ("packet signing disabled"));
}
/* BB should we turn on MAY flags for other MUST options? */
return count; return count;
} }
/* static int
ntlmv2_enabled_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len;
len = sprintf(page, "%d\n", ntlmv2_support);
len -= off;
*start = page + off;
if (len > count)
len = count;
else
*eof = 1;
if (len < 0)
len = 0;
return len;
}
static int
ntlmv2_enabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
if (c == '0' || c == 'n' || c == 'N')
ntlmv2_support = 0;
else if (c == '1' || c == 'y' || c == 'Y')
ntlmv2_support = 1;
else if (c == '2')
ntlmv2_support = 2;
return count;
}
static int
packet_signing_enabled_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len;
len = sprintf(page, "%d\n", sign_CIFS_PDUs);
len -= off;
*start = page + off;
if (len > count)
len = count;
else
*eof = 1;
if (len < 0)
len = 0;
return len;
}
static int
packet_signing_enabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
if (c == '0' || c == 'n' || c == 'N')
sign_CIFS_PDUs = 0;
else if (c == '1' || c == 'y' || c == 'Y')
sign_CIFS_PDUs = 1;
else if (c == '2')
sign_CIFS_PDUs = 2;
return count;
} */
#endif #endif

View file

@ -5,7 +5,7 @@
* Convert a unicode character to upper or lower case using * Convert a unicode character to upper or lower case using
* compressed tables. * compressed tables.
* *
* Copyright (c) International Business Machines Corp., 2000,2005555555555555555555555555555555555555555555555555555555 * Copyright (c) International Business Machines Corp., 2000,2007
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -142,7 +142,8 @@ UniStrlen(const wchar_t * ucs1)
} }
/* /*
* UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited) * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
* string (length limited)
*/ */
static inline size_t static inline size_t
UniStrnlen(const wchar_t *ucs1, int maxlen) UniStrnlen(const wchar_t *ucs1, int maxlen)

View file

@ -29,7 +29,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/random.h> #include <linux/random.h>
/* Calculate and return the CIFS signature based on the mac key and the smb pdu */ /* Calculate and return the CIFS signature based on the mac key and SMB PDU */
/* the 16 byte signature must be allocated by the caller */ /* the 16 byte signature must be allocated by the caller */
/* Note we only use the 1st eight bytes */ /* Note we only use the 1st eight bytes */
/* Note that the smb header signature field on input contains the /* Note that the smb header signature field on input contains the
@ -41,16 +41,17 @@ extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24); unsigned char *p24);
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
const char * key, char * signature) const struct mac_key *key, char *signature)
{ {
struct MD5Context context; struct MD5Context context;
if((cifs_pdu == NULL) || (signature == NULL)) if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL))
return -EINVAL; return -EINVAL;
MD5Init(&context); MD5Init(&context);
MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); MD5Update(&context, (char *)&key->data, key->len);
MD5Update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); MD5Update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
MD5Final(signature, &context); MD5Final(signature, &context);
return 0; return 0;
} }
@ -68,14 +69,16 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
return rc; return rc;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number); cifs_pdu->Signature.Sequence.SequenceNumber =
cpu_to_le32(server->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0; cifs_pdu->Signature.Sequence.Reserved = 0;
*pexpected_response_sequence_number = server->sequence_number++; *pexpected_response_sequence_number = server->sequence_number++;
server->sequence_number++; server->sequence_number++;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature); rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key,
smb_signature);
if (rc) if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8); memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else else
@ -85,16 +88,16 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
} }
static int cifs_calc_signature2(const struct kvec *iov, int n_vec, static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
const char * key, char * signature) const struct mac_key *key, char *signature)
{ {
struct MD5Context context; struct MD5Context context;
int i; int i;
if((iov == NULL) || (signature == NULL)) if ((iov == NULL) || (signature == NULL) || (key == NULL))
return -EINVAL; return -EINVAL;
MD5Init(&context); MD5Init(&context);
MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); MD5Update(&context, (char *)&key->data, key->len);
for (i = 0; i < n_vec; i++) { for (i = 0; i < n_vec; i++) {
if (iov[i].iov_base == NULL) { if (iov[i].iov_base == NULL) {
cERROR(1, ("null iovec entry")); cERROR(1, ("null iovec entry"));
@ -106,7 +109,8 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
if (i == 0) { if (i == 0) {
if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */ if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */
break; /* nothing to sign or corrupt header */ break; /* nothing to sign or corrupt header */
MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4); MD5Update(&context, iov[0].iov_base+4,
iov[0].iov_len-4);
} else } else
MD5Update(&context, iov[i].iov_base, iov[i].iov_len); MD5Update(&context, iov[i].iov_base, iov[i].iov_len);
} }
@ -139,7 +143,7 @@ int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server,
server->sequence_number++; server->sequence_number++;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key, rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key,
smb_signature); smb_signature);
if (rc) if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8); memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
@ -147,10 +151,10 @@ int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server,
memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
return rc; return rc;
} }
int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, int cifs_verify_signature(struct smb_hdr *cifs_pdu,
const struct mac_key *mac_key,
__u32 expected_sequence_number) __u32 expected_sequence_number)
{ {
unsigned int rc; unsigned int rc;
@ -164,23 +168,26 @@ int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
return 0; return 0;
if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; struct smb_com_lock_req *pSMB =
(struct smb_com_lock_req *)cifs_pdu;
if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
return 0; return 0;
} }
/* BB what if signatures are supposed to be on for session but server does not /* BB what if signatures are supposed to be on for session but
send one? BB */ server does not send one? BB */
/* Do not need to verify session setups with signature "BSRSPYL " */ /* Do not need to verify session setups with signature "BSRSPYL " */
if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0) if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); cFYI(1, ("dummy signature received for smb command 0x%x",
cifs_pdu->Command));
/* save off the origiginal signature so we can modify the smb and check /* save off the origiginal signature so we can modify the smb and check
its signature against what the server sent */ its signature against what the server sent */
memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8); memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.SequenceNumber =
cpu_to_le32(expected_sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0; cifs_pdu->Signature.Sequence.Reserved = 0;
rc = cifs_calculate_signature(cifs_pdu, mac_key, rc = cifs_calculate_signature(cifs_pdu, mac_key,
@ -189,8 +196,8 @@ int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
if (rc) if (rc)
return rc; return rc;
/* cifs_dump_mem("what we think it should be: ",
/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ what_we_think_sig_should_be, 16); */
if (memcmp(server_response_sig, what_we_think_sig_should_be, 8)) if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
return -EACCES; return -EACCES;
@ -200,15 +207,17 @@ int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
} }
/* We fill in key by putting in 40 byte array which was allocated by caller */ /* We fill in key by putting in 40 byte array which was allocated by caller */
int cifs_calculate_mac_key(char * key, const char * rn, const char * password) int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
const char *password)
{ {
char temp_key[16]; char temp_key[16];
if ((key == NULL) || (rn == NULL)) if ((key == NULL) || (rn == NULL))
return -EINVAL; return -EINVAL;
E_md4hash(password, temp_key); E_md4hash(password, temp_key);
mdfour(key,temp_key,16); mdfour(key->data.ntlm, temp_key, 16);
memcpy(key+16,rn, CIFS_SESS_KEY_SIZE); memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE);
key->len = 40;
return 0; return 0;
} }
@ -248,20 +257,22 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses,
for (i = 0; i < user_name_len; i++) for (i = 0; i < user_name_len; i++)
ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]];
ucase_buf[i] = 0; ucase_buf[i] = 0;
user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf,
MAX_USERNAME_SIZE*2, nls_info);
unicode_buf[user_name_len] = 0; unicode_buf[user_name_len] = 0;
user_name_len++; user_name_len++;
for (i = 0; i < dom_name_len; i++) for (i = 0; i < dom_name_len; i++)
ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]];
ucase_buf[i] = 0; ucase_buf[i] = 0;
dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf,
MAX_USERNAME_SIZE*2, nls_info);
unicode_buf[user_name_len + dom_name_len] = 0; unicode_buf[user_name_len + dom_name_len] = 0;
hmac_md5_update((const unsigned char *) unicode_buf, hmac_md5_update((const unsigned char *) unicode_buf,
(user_name_len+dom_name_len)*2, &ctx); (user_name_len+dom_name_len)*2, &ctx);
hmac_md5_final(ses->server->mac_signing_key,&ctx); hmac_md5_final(ses->server->ntlmv2_hash, &ctx);
kfree(ucase_buf); kfree(ucase_buf);
kfree(unicode_buf); kfree(unicode_buf);
return 0; return 0;
@ -282,7 +293,8 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
if (extended_security & CIFSSEC_MAY_PLNTXT) { if (extended_security & CIFSSEC_MAY_PLNTXT) {
memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); memcpy(lnm_session_key, password_with_pad,
CIFS_ENCPWD_SIZE);
return; return;
} }
@ -345,7 +357,10 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
if (domain == NULL) if (domain == NULL)
goto calc_exit_1; goto calc_exit_1;
len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
UniStrupr(domain); /* the following line was removed since it didn't work well
with lower cased domain name that passed as an option.
Maybe converting the domain name earlier makes sense */
/* UniStrupr(domain); */
hmac_md5_update((char *)domain, 2*len, pctxt); hmac_md5_update((char *)domain, 2*len, pctxt);
@ -356,7 +371,7 @@ calc_exit_1:
calc_exit_2: calc_exit_2:
/* BB FIXME what about bytes 24 through 40 of the signing key? /* BB FIXME what about bytes 24 through 40 of the signing key?
compare with the NTLM example */ compare with the NTLM example */
hmac_md5_final(ses->server->mac_signing_key, pctxt); hmac_md5_final(ses->server->ntlmv2_hash, pctxt);
return rc; return rc;
} }
@ -366,6 +381,7 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
{ {
int rc; int rc;
struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf;
struct HMACMD5Context context;
buf->blob_signature = cpu_to_le32(0x00000101); buf->blob_signature = cpu_to_le32(0x00000101);
buf->reserved = 0; buf->reserved = 0;
@ -382,14 +398,24 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
if (rc) if (rc)
cERROR(1, ("could not get v2 hash rc %d", rc)); cERROR(1, ("could not get v2 hash rc %d", rc));
CalcNTLMv2_response(ses, resp_buf); CalcNTLMv2_response(ses, resp_buf);
/* now calculate the MAC key for NTLMv2 */
hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
hmac_md5_update(resp_buf, 16, &context);
hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context);
memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf,
sizeof(struct ntlmv2_resp));
ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp);
} }
void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response) void CalcNTLMv2_response(const struct cifsSesInfo *ses,
char *v2_session_response)
{ {
struct HMACMD5Context context; struct HMACMD5Context context;
/* rest of v2 struct already generated */ /* rest of v2 struct already generated */
memcpy(v2_session_response + 8, ses->server->cryptKey, 8); memcpy(v2_session_response + 8, ses->server->cryptKey, 8);
hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
hmac_md5_update(v2_session_response+8, hmac_md5_update(v2_session_response+8,
sizeof(struct ntlmv2_resp) - 8, &context); sizeof(struct ntlmv2_resp) - 8, &context);

View file

@ -71,16 +71,20 @@ static struct task_struct * dnotifyThread = NULL;
static const struct super_operations cifs_super_ops; static const struct super_operations cifs_super_ops;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0); module_param(CIFSMaxBufSize, int, 0);
MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). "
"Default: 16384 Range: 8192 to 130048");
unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
module_param(cifs_min_rcv, int, 0); module_param(cifs_min_rcv, int, 0);
MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64"); MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: "
"1 to 64");
unsigned int cifs_min_small = 30; unsigned int cifs_min_small = 30;
module_param(cifs_min_small, int, 0); module_param(cifs_min_small, int, 0);
MODULE_PARM_DESC(cifs_min_small,"Small network buffers in pool. Default: 30 Range: 2 to 256"); MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
"Range: 2 to 256");
unsigned int cifs_max_pending = CIFS_MAX_REQ; unsigned int cifs_max_pending = CIFS_MAX_REQ;
module_param(cifs_max_pending, int, 0); module_param(cifs_max_pending, int, 0);
MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
"Default: 50 Range: 2 to 256");
extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_req_poolp;
@ -114,12 +118,9 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_magic = CIFS_MAGIC_NUMBER; sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops; sb->s_op = &cifs_super_ops;
#ifdef CONFIG_CIFS_EXPERIMENTAL
if (experimEnabled != 0)
sb->s_export_op = &cifs_export_ops;
#endif /* EXPERIMENTAL */
/* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) /* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ sb->s_blocksize =
cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
#ifdef CONFIG_CIFS_QUOTA #ifdef CONFIG_CIFS_QUOTA
sb->s_qcop = &cifs_quotactl_ops; sb->s_qcop = &cifs_quotactl_ops;
#endif #endif
@ -139,6 +140,13 @@ cifs_read_super(struct super_block *sb, void *data,
goto out_no_root; goto out_no_root;
} }
#ifdef CONFIG_CIFS_EXPERIMENTAL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
cFYI(1, ("export ops supported"));
sb->s_export_op = &cifs_export_ops;
}
#endif /* EXPERIMENTAL */
return 0; return 0;
out_no_root: out_no_root:
@ -217,8 +225,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
bypassed it because we detected that this was an older LANMAN sess */ bypassed it because we detected that this was an older LANMAN sess */
if (rc) if (rc)
rc = SMBOldQFSInfo(xid, pTcon, buf); rc = SMBOldQFSInfo(xid, pTcon, buf);
/* /* int f_type;
int f_type;
__fsid_t f_fsid; __fsid_t f_fsid;
int f_namelen; */ int f_namelen; */
/* BB get from info in tcon struct at mount time call to QFSAttrInfo */ /* BB get from info in tcon struct at mount time call to QFSAttrInfo */
@ -309,10 +316,10 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
seq_printf(s, ",posixpaths"); seq_printf(s, ",posixpaths");
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
!(cifs_sb->tcon->ses->capabilities & CAP_UNIX)) !(cifs_sb->tcon->unix_ext))
seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
!(cifs_sb->tcon->ses->capabilities & CAP_UNIX)) !(cifs_sb->tcon->unix_ext))
seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",rsize=%d", cifs_sb->rsize);
seq_printf(s, ",wsize=%d", cifs_sb->wsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize);
@ -445,8 +452,7 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */ /* cancel_notify_requests(tcon); */
if (tcon->ses && tcon->ses->server) if (tcon->ses && tcon->ses->server) {
{
cFYI(1, ("wake up tasks now - umount begin not complete")); cFYI(1, ("wake up tasks now - umount begin not complete"));
wake_up_all(&tcon->ses->server->request_q); wake_up_all(&tcon->ses->server->request_q);
wake_up_all(&tcon->ses->server->response_q); wake_up_all(&tcon->ses->server->response_q);
@ -481,9 +487,10 @@ static const struct super_operations cifs_super_ops = {
.alloc_inode = cifs_alloc_inode, .alloc_inode = cifs_alloc_inode,
.destroy_inode = cifs_destroy_inode, .destroy_inode = cifs_destroy_inode,
/* .drop_inode = generic_delete_inode, /* .drop_inode = generic_delete_inode,
.delete_inode = cifs_delete_inode, *//* Do not need the above two functions .delete_inode = cifs_delete_inode, */ /* Do not need above two
unless later we add lazy close of inodes or unless the kernel forgets to call functions unless later we add lazy close of inodes or unless the
us with the same number of releases (closes) as opens */ kernel forgets to call us with the same number of releases (closes)
as opens */
.show_options = cifs_show_options, .show_options = cifs_show_options,
.umount_begin = cifs_umount_begin, .umount_begin = cifs_umount_begin,
.remount_fs = cifs_remount, .remount_fs = cifs_remount,
@ -876,7 +883,8 @@ static int cifs_oplock_thread(void * dummyarg)
/* mutex_lock(&inode->i_mutex);*/ /* mutex_lock(&inode->i_mutex);*/
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
rc = filemap_fdatawrite(inode->i_mapping); rc = filemap_fdatawrite(inode->i_mapping);
if (CIFS_I(inode)->clientCanCacheRead == 0) { if (CIFS_I(inode)->clientCanCacheRead
== 0) {
filemap_fdatawait(inode->i_mapping); filemap_fdatawait(inode->i_mapping);
invalidate_remote_inode(inode); invalidate_remote_inode(inode);
} }
@ -885,9 +893,10 @@ static int cifs_oplock_thread(void * dummyarg)
/* mutex_unlock(&inode->i_mutex);*/ /* mutex_unlock(&inode->i_mutex);*/
if (rc) if (rc)
CIFS_I(inode)->write_behind_rc = rc; CIFS_I(inode)->write_behind_rc = rc;
cFYI(1,("Oplock flush inode %p rc %d",inode,rc)); cFYI(1, ("Oplock flush inode %p rc %d",
inode, rc));
/* releasing a stale oplock after recent reconnection /* releasing stale oplock after recent reconnect
of smb session using a now incorrect file of smb session using a now incorrect file
handle is not a data integrity issue but do handle is not a data integrity issue but do
not bother sending an oplock release if session not bother sending an oplock release if session
@ -898,7 +907,8 @@ static int cifs_oplock_thread(void * dummyarg)
0 /* len */ , 0 /* offset */, 0, 0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE, 0, LOCKING_ANDX_OPLOCK_RELEASE,
0 /* wait flag */); 0 /* wait flag */);
cFYI(1,("Oplock release rc = %d ",rc)); cFYI(1,
("Oplock release rc = %d ", rc));
} }
} else } else
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
@ -1036,7 +1046,7 @@ init_cifs(void)
static void __exit static void __exit
exit_cifs(void) exit_cifs(void)
{ {
cFYI(0, ("In unregister ie exit_cifs")); cFYI(0, ("exit_cifs"));
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
cifs_proc_clean(); cifs_proc_clean();
#endif #endif
@ -1051,7 +1061,8 @@ exit_cifs(void)
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
MODULE_DESCRIPTION MODULE_DESCRIPTION
("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows"); ("VFS to access servers complying with the SNIA CIFS Specification "
"e.g. Samba and Windows");
MODULE_VERSION(CIFS_VERSION); MODULE_VERSION(CIFS_VERSION);
module_init(init_cifs) module_init(init_cifs)
module_exit(exit_cifs) module_exit(exit_cifs)

View file

@ -63,9 +63,9 @@ extern const struct inode_operations cifs_symlink_inode_ops;
/* Functions related to files and directories */ /* Functions related to files and directories */
extern const struct file_operations cifs_file_ops; extern const struct file_operations cifs_file_ops;
extern const struct file_operations cifs_file_direct_ops; /* if directio mount */ extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
extern const struct file_operations cifs_file_nobrl_ops; extern const struct file_operations cifs_file_nobrl_ops;
extern const struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */ extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */
extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_open(struct inode *inode, struct file *file);
extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file);
extern int cifs_closedir(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file);
@ -88,7 +88,8 @@ extern struct dentry_operations cifs_ci_dentry_ops;
/* Functions related to symlinks */ /* Functions related to symlinks */
extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *); extern void cifs_put_link(struct dentry *direntry,
struct nameidata *nd, void *);
extern int cifs_readlink(struct dentry *direntry, char __user *buffer, extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
int buflen); int buflen);
extern int cifs_symlink(struct inode *inode, struct dentry *direntry, extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
@ -100,5 +101,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl (struct inode *inode, struct file *filep, extern int cifs_ioctl (struct inode *inode, struct file *filep,
unsigned int command, unsigned long arg); unsigned int command, unsigned long arg);
#define CIFS_VERSION "1.49" #define CIFS_VERSION "1.50"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */

View file

@ -1,7 +1,7 @@
/* /*
* fs/cifs/cifsglob.h * fs/cifs/cifsglob.h
* *
* Copyright (C) International Business Machines Corp., 2002,2006 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org) * Jeremy Allison (jra@samba.org)
* *
@ -28,7 +28,7 @@
#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1 #define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1
#define MAX_SERVER_SIZE 15 #define MAX_SERVER_SIZE 15
#define MAX_SHARE_SIZE 64 /* used to be 20 - this should still be enough */ #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */
#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null
termination then *2 for unicode versions */ termination then *2 for unicode versions */
#define MAX_PASSWORD_SIZE 16 #define MAX_PASSWORD_SIZE 16
@ -104,6 +104,17 @@ enum protocolEnum {
/* Netbios frames protocol not supported at this time */ /* Netbios frames protocol not supported at this time */
}; };
struct mac_key {
unsigned int len;
union {
char ntlm[CIFS_SESS_KEY_SIZE + 16];
struct {
char key[16];
struct ntlmv2_resp resp;
} ntlmv2;
} data;
};
/* /*
***************************************************************** *****************************************************************
* Except the CIFS PDUs themselves all the * Except the CIFS PDUs themselves all the
@ -159,7 +170,8 @@ struct TCP_Server_Info {
/* 16th byte of RFC1001 workstation name is always null */ /* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */ __u32 sequence_number; /* needed for CIFS PDU signature */
char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; struct mac_key mac_signing_key;
char ntlmv2_hash[16];
unsigned long lstrp; /* when we got last response from this server */ unsigned long lstrp; /* when we got last response from this server */
}; };
@ -269,7 +281,9 @@ struct cifsTconInfo {
FILE_SYSTEM_UNIX_INFO fsUnixInfo; FILE_SYSTEM_UNIX_INFO fsUnixInfo;
unsigned retry:1; unsigned retry:1;
unsigned nocase:1; unsigned nocase:1;
/* BB add field for back pointer to sb struct? */ unsigned unix_ext:1; /* if off disable Linux extensions to CIFS protocol
for this mount even if server would support */
/* BB add field for back pointer to sb struct(s)? */
}; };
/* /*
@ -327,7 +341,7 @@ struct cifsFileInfo {
struct cifsInodeInfo { struct cifsInodeInfo {
struct list_head lockList; struct list_head lockList;
/* BB add in lists for dirty pages - i.e. write caching info for oplock */ /* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList; struct list_head openFileList;
int write_behind_rc; int write_behind_rc;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */

View file

@ -366,17 +366,19 @@ struct smb_hdr {
#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 )
/* /*
* Computer Name Length * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
* No longer as important, now that TCP names are more commonly used to
* resolve hosts.
*/ */
#define CNLEN 15 #define CNLEN 15
/* /*
* Share Name Length @S8A * Share Name Length (SNLEN)
* Note: This length is limited by the SMB used to get @S8A * Note: This length was limited by the SMB used to get
* the Share info. NetShareEnum only returns 13 @S8A * the Share info. NetShareEnum only returned 13
* chars, including the null termination. @S8A * chars, including the null termination.
* This was removed because it no longer is limiting.
*/ */
#define SNLEN 12 /*@S8A */
/* /*
* Comment Length * Comment Length
@ -712,6 +714,7 @@ typedef struct smb_com_findclose_req {
#define REQ_OPLOCK 0x00000002 #define REQ_OPLOCK 0x00000002
#define REQ_BATCHOPLOCK 0x00000004 #define REQ_BATCHOPLOCK 0x00000004
#define REQ_OPENDIRONLY 0x00000008 #define REQ_OPENDIRONLY 0x00000008
#define REQ_EXTENDED_INFO 0x00000010
typedef struct smb_com_open_req { /* also handles create */ typedef struct smb_com_open_req { /* also handles create */
struct smb_hdr hdr; /* wct = 24 */ struct smb_hdr hdr; /* wct = 24 */
@ -818,7 +821,8 @@ typedef struct smb_com_writex_req {
__le16 DataLengthLow; __le16 DataLengthLow;
__le16 DataOffset; __le16 DataOffset;
__le16 ByteCount; __le16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ __u8 Pad; /* BB check for whether padded to DWORD
boundary and optimum performance here */
char Data[0]; char Data[0];
} __attribute__((packed)) WRITEX_REQ; } __attribute__((packed)) WRITEX_REQ;
@ -837,7 +841,8 @@ typedef struct smb_com_write_req {
__le16 DataOffset; __le16 DataOffset;
__le32 OffsetHigh; __le32 OffsetHigh;
__le16 ByteCount; __le16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ __u8 Pad; /* BB check for whether padded to DWORD
boundary and optimum performance here */
char Data[0]; char Data[0];
} __attribute__((packed)) WRITE_REQ; } __attribute__((packed)) WRITE_REQ;
@ -896,7 +901,8 @@ typedef struct smb_com_read_rsp {
__le16 DataLengthHigh; __le16 DataLengthHigh;
__u64 Reserved2; __u64 Reserved2;
__u16 ByteCount; __u16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ __u8 Pad; /* BB check for whether padded to DWORD
boundary and optimum performance here */
char Data[1]; char Data[1];
} __attribute__((packed)) READ_RSP; } __attribute__((packed)) READ_RSP;
@ -1743,7 +1749,9 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
__u8 Reserved3; __u8 Reserved3;
__le16 SubCommand; /* one setup word */ __le16 SubCommand; /* one setup word */
__le16 ByteCount; __le16 ByteCount;
__u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ __u8 Pad[3]; /* Win2K has sent 0x0F01 (max response length
perhaps?) followed by one byte pad - doesn't
seem to matter though */
__le16 MaxReferralLevel; __le16 MaxReferralLevel;
char RequestFileName[1]; char RequestFileName[1];
} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
@ -1752,7 +1760,10 @@ typedef struct dfs_referral_level_3 {
__le16 VersionNumber; __le16 VersionNumber;
__le16 ReferralSize; __le16 ReferralSize;
__le16 ServerType; /* 0x0001 = CIFS server */ __le16 ServerType; /* 0x0001 = CIFS server */
__le16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ __le16 ReferralFlags; /* or proximity - not clear which since it is
always set to zero - SNIA spec says 0x01
means strip off PathConsumed chars before
submitting RequestFileName to remote node */
__le16 TimeToLive; __le16 TimeToLive;
__le16 Proximity; __le16 Proximity;
__le16 DfsPathOffset; __le16 DfsPathOffset;
@ -1778,11 +1789,13 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp {
#define DFSREF_STORAGE_SERVER 0x0002 #define DFSREF_STORAGE_SERVER 0x0002
/* IOCTL information */ /* IOCTL information */
/* List of ioctl function codes that look to be of interest to remote clients like this. */ /*
/* Need to do some experimentation to make sure they all work remotely. */ * List of ioctl function codes that look to be of interest to remote clients
/* Some of the following such as the encryption/compression ones would be */ * like this one. Need to do some experimentation to make sure they all work
/* invoked from tools via a specialized hook into the VFS rather than via the */ * remotely. Some of the following, such as the encryption/compression ones
/* standard vfs entry points */ * would be invoked from tools via a specialized hook into the VFS rather
* than via the standard vfs entry points
*/
#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 #define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 #define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 #define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008
@ -1871,7 +1884,7 @@ typedef struct {
__le16 MajorVersionNumber; __le16 MajorVersionNumber;
__le16 MinorVersionNumber; __le16 MinorVersionNumber;
__le64 Capability; __le64 Capability;
} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ } __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/
/* Version numbers for CIFS UNIX major and minor. */ /* Version numbers for CIFS UNIX major and minor. */
#define CIFS_UNIX_MAJOR_VERSION 1 #define CIFS_UNIX_MAJOR_VERSION 1
@ -1886,14 +1899,18 @@ typedef struct {
#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based #define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based
calls including posix open calls including posix open
and posix unlink */ and posix unlink */
#define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up
to 0xFFFF00 */
#define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
/* Can not set pathnames cap yet until we send new posix create SMB since /* Can not set pathnames cap yet until we send new posix create SMB since
otherwise server can treat such handles opened with older ntcreatex otherwise server can treat such handles opened with older ntcreatex
(by a new client which knows how to send posix path ops) (by a new client which knows how to send posix path ops)
as non-posix handles (can affect write behavior with byte range locks. as non-posix handles (can affect write behavior with byte range locks.
We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */ We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */
/* #define CIFS_UNIX_CAP_MASK 0x0000003b */ /* #define CIFS_UNIX_CAP_MASK 0x000000fb */
#define CIFS_UNIX_CAP_MASK 0x0000001b #define CIFS_UNIX_CAP_MASK 0x000000db
#else #else
#define CIFS_UNIX_CAP_MASK 0x00000013 #define CIFS_UNIX_CAP_MASK 0x00000013
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
@ -2138,6 +2155,12 @@ typedef struct {
/* struct following varies based on requested level */ /* struct following varies based on requested level */
} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
#define SMB_POSIX_UNLINK_FILE_TARGET 0
#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
struct unlink_psx_rq { /* level 0x20a SetPathInfo */
__le16 type;
} __attribute__((packed));
struct file_internal_info { struct file_internal_info {
__u64 UniqueId; /* inode number */ __u64 UniqueId; /* inode number */
@ -2357,8 +2380,10 @@ struct data_blob {
T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2) T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK) T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) BB check for missing
Actually need QUERY_FILE_UNIX_INFO since has inode num inode fields
Actually a need QUERY_FILE_UNIX_INFO
since has inode num
BB what about a) blksize/blkbits/blocks BB what about a) blksize/blkbits/blocks
b) i_version b) i_version
c) i_rdev c) i_rdev
@ -2368,8 +2393,6 @@ struct data_blob {
T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
*/ */
/* xsymlink is a symlink format (used by MacOS) that can be used /* xsymlink is a symlink format (used by MacOS) that can be used
@ -2405,7 +2428,8 @@ typedef struct file_xattr_info {
__u32 xattr_value_len; __u32 xattr_value_len;
char xattr_name[0]; char xattr_name[0];
/* followed by xattr_value[xattr_value_len], no pad */ /* followed by xattr_value[xattr_value_len], no pad */
} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ } __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
level 0x205 */
/* flags for chattr command */ /* flags for chattr command */
@ -2431,7 +2455,8 @@ typedef struct file_xattr_info {
typedef struct file_chattr_info { typedef struct file_chattr_info {
__le64 mask; /* list of all possible attribute bits */ __le64 mask; /* list of all possible attribute bits */
__le64 mode; /* list of actual attribute bits on this inode */ __le64 mode; /* list of actual attribute bits on this inode */
} __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ } __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes
(chattr, chflags) level 0x206 */
#endif #endif

View file

@ -196,7 +196,10 @@ extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
const char *name, const struct nls_table *nls_codepage, const char *name, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon,
const char *name, __u16 type,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
const char *name, const char *name,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
@ -294,9 +297,11 @@ extern void tconInfoFree(struct cifsTconInfo *);
extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
__u32 *); __u32 *);
extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_verify_signature(struct smb_hdr *,
const struct mac_key *mac_key,
__u32 expected_sequence_number); __u32 expected_sequence_number);
extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
const char *pass);
extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *,
const struct nls_table *); const struct nls_table *);
extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * ); extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * );

View file

@ -132,21 +132,24 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* Give Demultiplex thread up to 10 seconds to /* Give Demultiplex thread up to 10 seconds to
reconnect, should be greater than cifs socket reconnect, should be greater than cifs socket
timeout which is 7 seconds */ timeout which is 7 seconds */
while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { while (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) {
wait_event_interruptible_timeout(tcon->ses->server->response_q, wait_event_interruptible_timeout(tcon->ses->server->response_q,
(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); (tcon->ses->server->tcpStatus ==
if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { CifsGood), 10 * HZ);
if (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) {
/* on "soft" mounts we wait once */ /* on "soft" mounts we wait once */
if ((tcon->retry == FALSE) || if ((tcon->retry == FALSE) ||
(tcon->ses->status == CifsExiting)) { (tcon->ses->status == CifsExiting)) {
cFYI(1,("gave up waiting on reconnect in smb_init")); cFYI(1, ("gave up waiting on "
"reconnect in smb_init"));
return -EHOSTDOWN; return -EHOSTDOWN;
} /* else "hard" mount - keep retrying } /* else "hard" mount - keep retrying
until process is killed or server until process is killed or server
comes back on-line */ comes back on-line */
} else /* TCP session is reestablished now */ } else /* TCP session is reestablished now */
break; break;
} }
nls_codepage = load_nls_default(); nls_codepage = load_nls_default();
@ -174,8 +177,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
atomic_inc(&tconInfoReconnectCount); atomic_inc(&tconInfoReconnectCount);
cFYI(1, ("reconnect tcon rc = %d", rc)); cFYI(1, ("reconnect tcon rc = %d", rc));
/* Removed call to reopen open files here - /* Removed call to reopen open files here.
it is safer (and faster) to reopen files It is safer (and faster) to reopen files
one at a time as needed in read and write */ one at a time as needed in read and write */
/* Check if handle based operation so we /* Check if handle based operation so we
@ -209,7 +212,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
return -ENOMEM; return -ENOMEM;
} }
header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); header_assemble((struct smb_hdr *) *request_buf, smb_command,
tcon, wct);
if (tcon != NULL) if (tcon != NULL)
cifs_stats_inc(&tcon->num_smbs_sent); cifs_stats_inc(&tcon->num_smbs_sent);
@ -274,24 +278,25 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* Give Demultiplex thread up to 10 seconds to /* Give Demultiplex thread up to 10 seconds to
reconnect, should be greater than cifs socket reconnect, should be greater than cifs socket
timeout which is 7 seconds */ timeout which is 7 seconds */
while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { while (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) {
wait_event_interruptible_timeout(tcon->ses->server->response_q, wait_event_interruptible_timeout(tcon->ses->server->response_q,
(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); (tcon->ses->server->tcpStatus ==
CifsGood), 10 * HZ);
if (tcon->ses->server->tcpStatus == if (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) { CifsNeedReconnect) {
/* on "soft" mounts we wait once */ /* on "soft" mounts we wait once */
if ((tcon->retry == FALSE) || if ((tcon->retry == FALSE) ||
(tcon->ses->status == CifsExiting)) { (tcon->ses->status == CifsExiting)) {
cFYI(1,("gave up waiting on reconnect in smb_init")); cFYI(1, ("gave up waiting on "
"reconnect in smb_init"));
return -EHOSTDOWN; return -EHOSTDOWN;
} /* else "hard" mount - keep retrying } /* else "hard" mount - keep retrying
until process is killed or server until process is killed or server
comes on-line */ comes on-line */
} else /* TCP session is reestablished now */ } else /* TCP session is reestablished now */
break; break;
} }
nls_codepage = load_nls_default(); nls_codepage = load_nls_default();
/* need to prevent multiple threads trying to /* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */ simultaneously reconnect the same SMB session */
@ -317,8 +322,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
atomic_inc(&tconInfoReconnectCount); atomic_inc(&tconInfoReconnectCount);
cFYI(1, ("reconnect tcon rc = %d", rc)); cFYI(1, ("reconnect tcon rc = %d", rc));
/* Removed call to reopen open files here - /* Removed call to reopen open files here.
it is safer (and faster) to reopen files It is safer (and faster) to reopen files
one at a time as needed in read and write */ one at a time as needed in read and write */
/* Check if handle based operation so we /* Check if handle based operation so we
@ -382,7 +387,8 @@ static int validate_t2(struct smb_t2_rsp * pSMB)
/* check that bcc is less than negotiated smb buffer */ /* check that bcc is less than negotiated smb buffer */
total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
if (total_size < 512) { if (total_size < 512) {
total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount); total_size +=
le16_to_cpu(pSMB->t2_rsp.DataCount);
/* BCC le converted in SendReceive */ /* BCC le converted in SendReceive */
pBCC = (pSMB->hdr.WordCount * 2) + pBCC = (pSMB->hdr.WordCount * 2) +
sizeof(struct smb_hdr) + sizeof(struct smb_hdr) +
@ -392,7 +398,6 @@ static int validate_t2(struct smb_t2_rsp * pSMB)
CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
return 0; return 0;
} }
} }
} }
} }
@ -426,7 +431,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
/* if any of auth flags (ie not sign or seal) are overriden use them */ /* if any of auth flags (ie not sign or seal) are overriden use them */
if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
secFlags = ses->overrideSecFlg; secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
else /* if override flags set only sign/seal OR them with global auth */ else /* if override flags set only sign/seal OR them with global auth */
secFlags = extended_security | ses->overrideSecFlg; secFlags = extended_security | ses->overrideSecFlg;
@ -504,7 +509,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
utc = CURRENT_TIME; utc = CURRENT_TIME;
ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date), ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
le16_to_cpu(rsp->SrvTime.Time)); le16_to_cpu(rsp->SrvTime.Time));
cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d", cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
(int)ts.tv_sec, (int)utc.tv_sec, (int)ts.tv_sec, (int)utc.tv_sec,
(int)(utc.tv_sec - ts.tv_sec))); (int)(utc.tv_sec - ts.tv_sec)));
val = (int)(utc.tv_sec - ts.tv_sec); val = (int)(utc.tv_sec - ts.tv_sec);
@ -633,22 +638,33 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
#ifdef CONFIG_CIFS_WEAK_PW_HASH #ifdef CONFIG_CIFS_WEAK_PW_HASH
signing_check: signing_check:
#endif #endif
if(sign_CIFS_PDUs == FALSE) { if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
/* MUST_SIGN already includes the MAY_SIGN FLAG
so if this is zero it means that signing is disabled */
cFYI(1, ("Signing disabled"));
if (server->secMode & SECMODE_SIGN_REQUIRED) if (server->secMode & SECMODE_SIGN_REQUIRED)
cERROR(1, ("Server requires " cERROR(1, ("Server requires "
"/proc/fs/cifs/PacketSigningEnabled to be on")); "/proc/fs/cifs/PacketSigningEnabled "
"to be on"));
server->secMode &= server->secMode &=
~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
} else if(sign_CIFS_PDUs == 1) { } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
/* signing required */
cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
if ((server->secMode &
(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
cERROR(1,
("signing required but server lacks support"));
rc = -EOPNOTSUPP;
} else
server->secMode |= SECMODE_SIGN_REQUIRED;
} else {
/* signing optional ie CIFSSEC_MAY_SIGN */
if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0) if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
server->secMode &= server->secMode &=
~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
} else if(sign_CIFS_PDUs == 2) {
if((server->secMode &
(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
cERROR(1,("signing required but server lacks support"));
}
} }
neg_err_exit: neg_err_exit:
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
@ -779,6 +795,82 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
return rc; return rc;
} }
int
CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
__u16 type, const struct nls_table *nls_codepage, int remap)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
struct unlink_psx_rq *pRqD;
int name_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, param_offset, offset, byte_count;
cFYI(1, ("In POSIX delete"));
PsxDelete:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB add path length overrun check */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, fileName, name_len);
}
params = 6 + name_len;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = 0; /* BB double check this with jra */
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
InformationLevel) - 4;
offset = param_offset + params;
/* Setup pointer to Request Data (inode type) */
pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
pRqD->type = cpu_to_le16(type);
pSMB->ParameterOffset = cpu_to_le16(param_offset);
pSMB->DataOffset = cpu_to_le16(offset);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cFYI(1, ("Posix delete returned %d", rc));
}
cifs_buf_release(pSMB);
cifs_stats_inc(&tcon->num_deletes);
if (rc == -EAGAIN)
goto PsxDelete;
return rc;
}
int int
CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
const struct nls_table *nls_codepage, int remap) const struct nls_table *nls_codepage, int remap)
@ -924,7 +1016,6 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
int name_len; int name_len;
int rc = 0; int rc = 0;
int bytes_returned = 0; int bytes_returned = 0;
char *data_offset;
__u16 params, param_offset, offset, byte_count, count; __u16 params, param_offset, offset, byte_count, count;
OPEN_PSX_REQ * pdata; OPEN_PSX_REQ * pdata;
OPEN_PSX_RSP * psx_rsp; OPEN_PSX_RSP * psx_rsp;
@ -960,7 +1051,6 @@ PsxCreat:
param_offset = offsetof(struct smb_com_transaction2_spi_req, param_offset = offsetof(struct smb_com_transaction2_spi_req,
InformationLevel) - 4; InformationLevel) - 4;
offset = param_offset + params; offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset); pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
pdata->Level = SMB_QUERY_FILE_UNIX_BASIC; pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
pdata->Permissions = cpu_to_le64(mode); pdata->Permissions = cpu_to_le64(mode);
@ -1025,7 +1115,6 @@ PsxCreat:
sizeof (FILE_UNIX_BASIC_INFO)); sizeof (FILE_UNIX_BASIC_INFO));
} }
psx_create_err: psx_create_err:
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
@ -1132,7 +1221,8 @@ OldOpenRetry:
being created */ being created */
/* BB FIXME BB */ /* BB FIXME BB */
/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */ /* pSMB->CreateOptions = cpu_to_le32(create_options &
CREATE_OPTIONS_MASK); */
/* BB FIXME END BB */ /* BB FIXME END BB */
pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
@ -1285,10 +1375,9 @@ openRetry:
} }
int int
CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
const int netfid, const unsigned int count, const unsigned int count, const __u64 lseek, unsigned int *nbytes,
const __u64 lseek, unsigned int *nbytes, char **buf, char **buf, int *pbuf_type)
int * pbuf_type)
{ {
int rc = -EACCES; int rc = -EACCES;
READ_REQ *pSMB = NULL; READ_REQ *pSMB = NULL;
@ -1351,7 +1440,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
/*check that DataLength would not go beyond end of SMB */ /*check that DataLength would not go beyond end of SMB */
if ((data_length > CIFSMaxBufSize) if ((data_length > CIFSMaxBufSize)
|| (data_length > count)) { || (data_length > count)) {
cFYI(1,("bad length %d for count %d",data_length,count)); cFYI(1, ("bad length %d for count %d",
data_length, count));
rc = -EIO; rc = -EIO;
*nbytes = 0; *nbytes = 0;
} else { } else {
@ -1422,14 +1512,14 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
if (wct == 14) if (wct == 14)
pSMB->OffsetHigh = cpu_to_le32(offset >> 32); pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
else if((offset >> 32) > 0) /* can not handle this big offset for old */ else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
return -EIO; return -EIO;
pSMB->Reserved = 0xFFFFFFFF; pSMB->Reserved = 0xFFFFFFFF;
pSMB->WriteMode = 0; pSMB->WriteMode = 0;
pSMB->Remaining = 0; pSMB->Remaining = 0;
/* Can increase buffer size if buffer is big enough in some cases - ie we /* Can increase buffer size if buffer is big enough in some cases ie we
can send more if LARGE_WRITE_X capability returned by the server and if can send more if LARGE_WRITE_X capability returned by the server and if
our buffer is big enough or if we convert to iovecs on socket writes our buffer is big enough or if we convert to iovecs on socket writes
and eliminate the copy to the CIFS buffer */ and eliminate the copy to the CIFS buffer */
@ -1467,7 +1557,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
if (wct == 14) if (wct == 14)
pSMB->ByteCount = cpu_to_le16(byte_count); pSMB->ByteCount = cpu_to_le16(byte_count);
else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */ else { /* old style write has byte count 4 bytes earlier
so 4 bytes pad */
struct smb_com_writex_req *pSMBW = struct smb_com_writex_req *pSMBW =
(struct smb_com_writex_req *)pSMB; (struct smb_com_writex_req *)pSMB;
pSMBW->ByteCount = cpu_to_le16(byte_count); pSMBW->ByteCount = cpu_to_le16(byte_count);
@ -1523,7 +1614,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
if (wct == 14) if (wct == 14)
pSMB->OffsetHigh = cpu_to_le32(offset >> 32); pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
else if((offset >> 32) > 0) /* can not handle this big offset for old */ else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
return -EIO; return -EIO;
pSMB->Reserved = 0xFFFFFFFF; pSMB->Reserved = 0xFFFFFFFF;
pSMB->WriteMode = 0; pSMB->WriteMode = 0;
@ -1661,7 +1752,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
{ {
struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
char *data_offset;
struct cifs_posix_lock *parm_data; struct cifs_posix_lock *parm_data;
int rc = 0; int rc = 0;
int timeout = 0; int timeout = 0;
@ -1688,8 +1778,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
offset = param_offset + params; offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
count = sizeof(struct cifs_posix_lock); count = sizeof(struct cifs_posix_lock);
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
@ -1933,7 +2021,8 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
dummy_string, 24, nls_codepage, remap); dummy_string, 24, nls_codepage, remap);
} else { } else {
len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
target_name, PATH_MAX, nls_codepage, remap); target_name, PATH_MAX, nls_codepage,
remap);
} }
rename_info->target_name_len = cpu_to_le32(2 * len_of_str); rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
@ -1994,7 +2083,8 @@ copyRetry:
pSMB->OldFileName[name_len] = 0x04; /* pad */ pSMB->OldFileName[name_len] = 0x04; /* pad */
/* protocol requires ASCII signature byte on Unicode string */ /* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00; pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], name_len2 =
cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
toName, PATH_MAX, nls_codepage, remap); toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */ name_len2 *= 2; /* convert to bytes */
@ -2108,9 +2198,7 @@ createSymLinkRetry:
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_symlinks); cifs_stats_inc(&tcon->num_symlinks);
if (rc) { if (rc) {
cFYI(1, cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
("Send error in SetPathInfo (create symlink) = %d",
rc));
} }
if (pSMB) if (pSMB)
@ -2302,9 +2390,8 @@ querySymLinkRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = name_len =
cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
/* find define for this maxpathcomponent */ PATH_MAX, nls_codepage);
, nls_codepage);
name_len++; /* trailing null */ name_len++; /* trailing null */
name_len *= 2; name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */ } else { /* BB improve the check for buffer overruns BB */
@ -2359,8 +2446,8 @@ querySymLinkRetry:
min_t(const int, buflen, count) / 2); min_t(const int, buflen, count) / 2);
/* BB FIXME investigate remapping reserved chars here */ /* BB FIXME investigate remapping reserved chars here */
cifs_strfromUCS_le(symlinkinfo, cifs_strfromUCS_le(symlinkinfo,
(__le16 *) ((char *)&pSMBr->hdr.Protocol + (__le16 *) ((char *)&pSMBr->hdr.Protocol
data_offset), + data_offset),
name_len, nls_codepage); name_len, nls_codepage);
} else { } else {
strncpy(symlinkinfo, strncpy(symlinkinfo,
@ -2432,7 +2519,6 @@ validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
(char *)&pSMBr->ByteCount; (char *)&pSMBr->ByteCount;
data_offset = le32_to_cpu(pSMBr->DataOffset); data_offset = le32_to_cpu(pSMBr->DataOffset);
data_count = le32_to_cpu(pSMBr->DataCount); data_count = le32_to_cpu(pSMBr->DataCount);
parm_offset = le32_to_cpu(pSMBr->ParameterOffset); parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
@ -2453,7 +2539,8 @@ validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
return -EINVAL; return -EINVAL;
} else if (data_count + *ppdata > end_of_smb) { } else if (data_count + *ppdata > end_of_smb) {
cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p", cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
*ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */ *ppdata, data_count, (data_count + *ppdata),
end_of_smb, pSMBr));
return -EINVAL; return -EINVAL;
} else if (parm_count + data_count > pSMBr->ByteCount) { } else if (parm_count + data_count > pSMBr->ByteCount) {
cFYI(1, ("parm count and data count larger than SMB")); cFYI(1, ("parm count and data count larger than SMB"));
@ -2516,8 +2603,10 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
pSMBr->ByteCount + pSMBr->ByteCount +
(char *)&pSMBr->ByteCount; (char *)&pSMBr->ByteCount;
struct reparse_data * reparse_buf = (struct reparse_data *) struct reparse_data *reparse_buf =
((char *)&pSMBr->hdr.Protocol + data_offset); (struct reparse_data *)
((char *)&pSMBr->hdr.Protocol
+ data_offset);
if ((char *)reparse_buf >= end_of_smb) { if ((char *)reparse_buf >= end_of_smb) {
rc = -EIO; rc = -EIO;
goto qreparse_out; goto qreparse_out;
@ -2526,7 +2615,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
reparse_buf->TargetNameOffset + reparse_buf->TargetNameOffset +
reparse_buf->TargetNameLen) > reparse_buf->TargetNameLen) >
end_of_smb) { end_of_smb) {
cFYI(1,("reparse buf extended beyond SMB")); cFYI(1,("reparse buf goes beyond SMB"));
rc = -EIO; rc = -EIO;
goto qreparse_out; goto qreparse_out;
} }
@ -2535,19 +2624,23 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
name_len = UniStrnlen((wchar_t *) name_len = UniStrnlen((wchar_t *)
(reparse_buf->LinkNamesBuf + (reparse_buf->LinkNamesBuf +
reparse_buf->TargetNameOffset), reparse_buf->TargetNameOffset),
min(buflen/2, reparse_buf->TargetNameLen / 2)); min(buflen/2,
reparse_buf->TargetNameLen / 2));
cifs_strfromUCS_le(symlinkinfo, cifs_strfromUCS_le(symlinkinfo,
(__le16 *) (reparse_buf->LinkNamesBuf + (__le16 *) (reparse_buf->LinkNamesBuf +
reparse_buf->TargetNameOffset), reparse_buf->TargetNameOffset),
name_len, nls_codepage); name_len, nls_codepage);
} else { /* ASCII names */ } else { /* ASCII names */
strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + strncpy(symlinkinfo,
reparse_buf->LinkNamesBuf +
reparse_buf->TargetNameOffset, reparse_buf->TargetNameOffset,
min_t(const int, buflen, reparse_buf->TargetNameLen)); min_t(const int, buflen,
reparse_buf->TargetNameLen));
} }
} else { } else {
rc = -EIO; rc = -EIO;
cFYI(1,("Invalid return data count on get reparse info ioctl")); cFYI(1, ("Invalid return data count on "
"get reparse info ioctl"));
} }
symlinkinfo[buflen] = 0; /* just in case so the caller symlinkinfo[buflen] = 0; /* just in case so the caller
does not go off the end of the buffer */ does not go off the end of the buffer */
@ -2566,7 +2659,8 @@ qreparse_out:
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
/*Convert an Access Control Entry from wire format to local POSIX xattr format*/ /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace) static void cifs_convert_ace(posix_acl_xattr_entry *ace,
struct cifs_posix_ace *cifs_ace)
{ {
/* u8 cifs fields do not need le conversion */ /* u8 cifs fields do not need le conversion */
ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm); ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
@ -2598,7 +2692,8 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
size += sizeof(struct cifs_posix_ace) * count; size += sizeof(struct cifs_posix_ace) * count;
/* check if we would go beyond end of SMB */ /* check if we would go beyond end of SMB */
if (size_of_data_area < size) { if (size_of_data_area < size) {
cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size)); cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
size_of_data_area, size));
return -EINVAL; return -EINVAL;
} }
} else if (acl_type & ACL_TYPE_DEFAULT) { } else if (acl_type & ACL_TYPE_DEFAULT) {
@ -2650,8 +2745,8 @@ static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
} }
/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */ /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen, static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
const int acl_type) const int buflen, const int acl_type)
{ {
__u16 rc = 0; __u16 rc = 0;
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data; struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
@ -2663,7 +2758,8 @@ static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int bufl
return 0; return 0;
count = posix_acl_xattr_count((size_t)buflen); count = posix_acl_xattr_count((size_t)buflen);
cFYI(1,("setting acl with %d entries from buf of length %d and version of %d", cFYI(1, ("setting acl with %d entries from buf of length %d and "
"version of %d",
count, buflen, le32_to_cpu(local_acl->a_version))); count, buflen, le32_to_cpu(local_acl->a_version)));
if (le32_to_cpu(local_acl->a_version) != 2) { if (le32_to_cpu(local_acl->a_version) != 2) {
cFYI(1, ("unknown POSIX ACL version %d", cFYI(1, ("unknown POSIX ACL version %d",
@ -2742,7 +2838,8 @@ queryAclRetry:
pSMB->Timeout = 0; pSMB->Timeout = 0;
pSMB->Reserved2 = 0; pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16( pSMB->ParameterOffset = cpu_to_le16(
offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); offsetof(struct smb_com_transaction2_qpi_req,
InformationLevel) - 4);
pSMB->DataCount = 0; pSMB->DataCount = 0;
pSMB->DataOffset = 0; pSMB->DataOffset = 0;
pSMB->SetupCount = 1; pSMB->SetupCount = 1;
@ -2943,7 +3040,6 @@ GetExtAttrOut:
return rc; return rc;
} }
#endif /* CONFIG_POSIX */ #endif /* CONFIG_POSIX */
@ -3005,12 +3101,12 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
rc = validate_ntransact(iov[0].iov_base, (char **)&parm, rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
(char **)&psec_desc, (char **)&psec_desc,
&parm_len, &data_len); &parm_len, &data_len);
if (rc) if (rc)
goto qsec_out; goto qsec_out;
pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base; pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */ cERROR(1, ("smb %p parm %p data %p",
pSMBr, parm, psec_desc)); /* BB removeme BB */
if (le32_to_cpu(pSMBr->ParameterCount) != 4) { if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
rc = -EIO; /* bad smb */ rc = -EIO; /* bad smb */
@ -3176,13 +3272,15 @@ QPathInfoRetry:
else if (!legacy && (pSMBr->ByteCount < 40)) else if (!legacy && (pSMBr->ByteCount < 40))
rc = -EIO; /* bad smb */ rc = -EIO; /* bad smb */
else if (legacy && (pSMBr->ByteCount < 24)) else if (legacy && (pSMBr->ByteCount < 24))
rc = -EIO; /* 24 or 26 expected but we do not read last field */ rc = -EIO; /* 24 or 26 expected but we do not read
last field */
else if (pFindData) { else if (pFindData) {
int size; int size;
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
if(legacy) /* we do not read the last field, EAsize, fortunately if (legacy) /* we do not read the last field, EAsize,
since it varies by subdialect and on Set vs. Get, is fortunately since it varies by subdialect
two bytes or 4 bytes depending but we don't care here */ and on Set vs. Get, is two bytes or 4
bytes depending but we don't care here */
size = sizeof(FILE_INFO_STANDARD); size = sizeof(FILE_INFO_STANDARD);
else else
size = sizeof(FILE_ALL_INFO); size = sizeof(FILE_ALL_INFO);
@ -3303,9 +3401,8 @@ findUniqueRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = name_len =
cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
/* find define for this maxpathcomponent */ PATH_MAX, nls_codepage);
, nls_codepage);
name_len++; /* trailing null */ name_len++; /* trailing null */
name_len *= 2; name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */ } else { /* BB improve the check for buffer overruns BB */
@ -3485,7 +3582,8 @@ findFirstRetry:
else else
psrch_inf->endOfSearch = FALSE; psrch_inf->endOfSearch = FALSE;
psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->entries_in_buffer =
le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
psrch_inf->entries_in_buffer; psrch_inf->entries_in_buffer;
*pnetfid = parms->SearchHandle; *pnetfid = parms->SearchHandle;
@ -3523,7 +3621,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->TotalDataCount = 0; /* no EAs */ pSMB->TotalDataCount = 0; /* no EAs */
pSMB->MaxParameterCount = cpu_to_le16(8); pSMB->MaxParameterCount = cpu_to_le16(8);
pSMB->MaxDataCount = pSMB->MaxDataCount =
cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
0xFFFFFF00);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
@ -3539,15 +3638,6 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->SearchHandle = searchHandle; /* always kept as le */ pSMB->SearchHandle = searchHandle; /* always kept as le */
pSMB->SearchCount = pSMB->SearchCount =
cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO)); cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
/* test for Unix extensions */
/* if (tcon->ses->capabilities & CAP_UNIX) {
pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
psrch_inf->info_level = SMB_FIND_FILE_UNIX;
} else {
pSMB->InformationLevel =
cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
} */
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
pSMB->ResumeKey = psrch_inf->resume_key; pSMB->ResumeKey = psrch_inf->resume_key;
pSMB->SearchFlags = pSMB->SearchFlags =
@ -3577,7 +3667,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
if (rc) { if (rc) {
if (rc == -EBADF) { if (rc == -EBADF) {
psrch_inf->endOfSearch = TRUE; psrch_inf->endOfSearch = TRUE;
rc = 0; /* search probably was closed at end of search above */ rc = 0; /* search probably was closed at end of search*/
} else } else
cFYI(1, ("FindNext returned = %d", rc)); cFYI(1, ("FindNext returned = %d", rc));
} else { /* decode response */ } else { /* decode response */
@ -3606,11 +3696,12 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
psrch_inf->endOfSearch = TRUE; psrch_inf->endOfSearch = TRUE;
else else
psrch_inf->endOfSearch = FALSE; psrch_inf->endOfSearch = FALSE;
psrch_inf->entries_in_buffer =
psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry += psrch_inf->index_of_last_entry +=
psrch_inf->entries_in_buffer; psrch_inf->entries_in_buffer;
/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
/* BB fixme add unlock here */ /* BB fixme add unlock here */
} }
@ -3625,12 +3716,12 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
FNext2_err_exit: FNext2_err_exit:
if (rc != 0) if (rc != 0)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
return rc; return rc;
} }
int int
CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle) CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
const __u16 searchHandle)
{ {
int rc = 0; int rc = 0;
FINDCLOSE_REQ *pSMB = NULL; FINDCLOSE_REQ *pSMB = NULL;
@ -3687,7 +3778,6 @@ GetInodeNumberRetry:
if (rc) if (rc)
return rc; return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = name_len =
cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
@ -3852,26 +3942,35 @@ getDFSRetry:
/* BB Add logic to parse referrals here */ /* BB Add logic to parse referrals here */
rc = validate_t2((struct smb_t2_rsp *)pSMBr); rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */ /* BB Also check if enough total bytes returned? */
if (rc || (pSMBr->ByteCount < 17))
rc = -EIO; /* bad smb */ rc = -EIO; /* bad smb */
else { else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 data_count = le16_to_cpu(pSMBr->t2.DataCount); __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
cFYI(1, cFYI(1,
("Decoding GetDFSRefer response. BCC: %d Offset %d", ("Decoding GetDFSRefer response BCC: %d Offset %d",
pSMBr->ByteCount, data_offset)); pSMBr->ByteCount, data_offset));
referrals = referrals =
(struct dfs_referral_level_3 *) (struct dfs_referral_level_3 *)
(8 /* sizeof start of data block */ + (8 /* sizeof start of data block */ +
data_offset + data_offset +
(char *) &pSMBr->hdr.Protocol); (char *) &pSMBr->hdr.Protocol);
cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x", cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive))); "for referral one refer size: 0x%x srv "
"type: 0x%x refer flags: 0x%x ttl: 0x%x",
le16_to_cpu(pSMBr->NumberOfReferrals),
le16_to_cpu(pSMBr->DFSFlags),
le16_to_cpu(referrals->ReferralSize),
le16_to_cpu(referrals->ServerType),
le16_to_cpu(referrals->ReferralFlags),
le16_to_cpu(referrals->TimeToLive)));
/* BB This field is actually two bytes in from start of /* BB This field is actually two bytes in from start of
data block so we could do safety check that DataBlock data block so we could do safety check that DataBlock
begins at address of pSMBr->NumberOfReferrals */ begins at address of pSMBr->NumberOfReferrals */
*number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals); *number_of_UNC_in_array =
le16_to_cpu(pSMBr->NumberOfReferrals);
/* BB Fix below so can return more than one referral */ /* BB Fix below so can return more than one referral */
if (*number_of_UNC_in_array > 1) if (*number_of_UNC_in_array > 1)
@ -3881,7 +3980,8 @@ getDFSRetry:
name_len = 0; name_len = 0;
for (i = 0; i < *number_of_UNC_in_array; i++) { for (i = 0; i < *number_of_UNC_in_array; i++) {
/* make sure that DfsPathOffset not past end */ /* make sure that DfsPathOffset not past end */
__u16 offset = le16_to_cpu(referrals->DfsPathOffset); __u16 offset =
le16_to_cpu(referrals->DfsPathOffset);
if (offset > data_count) { if (offset > data_count) {
/* if invalid referral, stop here and do /* if invalid referral, stop here and do
not try to copy any more */ not try to copy any more */
@ -3891,33 +3991,36 @@ getDFSRetry:
temp = ((char *)referrals) + offset; temp = ((char *)referrals) + offset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len += UniStrnlen((wchar_t *)temp,data_count); name_len += UniStrnlen((wchar_t *)temp,
data_count);
} else { } else {
name_len += strnlen(temp, data_count); name_len += strnlen(temp, data_count);
} }
referrals++; referrals++;
/* BB add check that referral pointer does not fall off end PDU */ /* BB add check that referral pointer does
not fall off end PDU */
} }
/* BB add check for name_len bigger than bcc */ /* BB add check for name_len bigger than bcc */
*targetUNCs = *targetUNCs =
kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL); kmalloc(name_len+1+(*number_of_UNC_in_array),
GFP_KERNEL);
if (*targetUNCs == NULL) { if (*targetUNCs == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
goto GetDFSRefExit; goto GetDFSRefExit;
} }
/* copy the ref strings */ /* copy the ref strings */
referrals = referrals = (struct dfs_referral_level_3 *)
(struct dfs_referral_level_3 *) (8 /* sizeof data hdr */ + data_offset +
(8 /* sizeof data hdr */ +
data_offset +
(char *) &pSMBr->hdr.Protocol); (char *) &pSMBr->hdr.Protocol);
for (i = 0; i < *number_of_UNC_in_array; i++) { for (i = 0; i < *number_of_UNC_in_array; i++) {
temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset); temp = ((char *)referrals) +
le16_to_cpu(referrals->DfsPathOffset);
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
cifs_strfromUCS_le(*targetUNCs, cifs_strfromUCS_le(*targetUNCs,
(__le16 *) temp, name_len, nls_codepage); (__le16 *) temp,
name_len,
nls_codepage);
} else { } else {
strncpy(*targetUNCs, temp, name_len); strncpy(*targetUNCs, temp, name_len);
} }
@ -3999,8 +4102,7 @@ oldQFSInfoRetry:
cFYI(1, ("qfsinf resp BCC: %d Offset %d", cFYI(1, ("qfsinf resp BCC: %d Offset %d",
pSMBr->ByteCount, data_offset)); pSMBr->ByteCount, data_offset));
response_data = response_data = (FILE_SYSTEM_ALLOC_INFO *)
(FILE_SYSTEM_ALLOC_INFO *)
(((char *) &pSMBr->hdr.Protocol) + data_offset); (((char *) &pSMBr->hdr.Protocol) + data_offset);
FSData->f_bsize = FSData->f_bsize =
le16_to_cpu(response_data->BytesPerSector) * le16_to_cpu(response_data->BytesPerSector) *
@ -4153,7 +4255,8 @@ QFSAttributeRetry:
} else { /* decode response */ } else { /* decode response */
rc = validate_t2((struct smb_t2_rsp *)pSMBr); rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */ if (rc || (pSMBr->ByteCount < 13)) {
/* BB also check if enough bytes returned */
rc = -EIO; /* bad smb */ rc = -EIO; /* bad smb */
} else { } else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
@ -4335,7 +4438,8 @@ SETFSUnixRetry:
pSMB->Flags = 0; pSMB->Flags = 0;
pSMB->Timeout = 0; pSMB->Timeout = 0;
pSMB->Reserved2 = 0; pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4; param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
- 4;
offset = param_offset + params; offset = param_offset + params;
pSMB->MaxParameterCount = cpu_to_le16(4); pSMB->MaxParameterCount = cpu_to_le16(4);
@ -4614,8 +4718,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->ParameterOffset = cpu_to_le16(param_offset); pSMB->ParameterOffset = cpu_to_le16(param_offset);
parm_data = parm_data =
(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
offset); + offset);
pSMB->DataOffset = cpu_to_le16(offset); pSMB->DataOffset = cpu_to_le16(offset);
parm_data->FileSize = cpu_to_le64(size); parm_data->FileSize = cpu_to_le64(size);
pSMB->Fid = fid; pSMB->Fid = fid;
@ -4661,8 +4765,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
time and resort to the original setpathinfo level which takes the ancient time and resort to the original setpathinfo level which takes the ancient
DOS time format with 2 second granularity */ DOS time format with 2 second granularity */
int int
CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
__u16 fid) const FILE_BASIC_INFO *data, __u16 fid)
{ {
struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@ -5131,7 +5235,7 @@ QAllEAsRetry:
struct fealist *ea_response_data; struct fealist *ea_response_data;
rc = 0; rc = 0;
/* validate_trans2_offsets() */ /* validate_trans2_offsets() */
/* BB to check if(start of smb + data_offset > &bcc+ bcc)*/ /* BB check if start of smb + data_offset > &bcc+ bcc */
ea_response_data = (struct fealist *) ea_response_data = (struct fealist *)
(((char *) &pSMBr->hdr.Protocol) + (((char *) &pSMBr->hdr.Protocol) +
data_offset); data_offset);
@ -5155,7 +5259,8 @@ QAllEAsRetry:
if (rc < (int)buf_size) { if (rc < (int)buf_size) {
memcpy(EAData, "user.", 5); memcpy(EAData, "user.", 5);
EAData += 5; EAData += 5;
memcpy(EAData,temp_ptr,temp_fea->name_len); memcpy(EAData, temp_ptr,
temp_fea->name_len);
EAData += temp_fea->name_len; EAData += temp_fea->name_len;
/* null terminate name */ /* null terminate name */
*EAData = 0; *EAData = 0;
@ -5172,11 +5277,15 @@ QAllEAsRetry:
/* account for trailing null */ /* account for trailing null */
name_len--; name_len--;
temp_ptr++; temp_ptr++;
value_len = le16_to_cpu(temp_fea->value_len); value_len =
le16_to_cpu(temp_fea->value_len);
name_len -= value_len; name_len -= value_len;
temp_ptr += value_len; temp_ptr += value_len;
/* BB check that temp_ptr is still within smb BB*/ /* BB check that temp_ptr is still
/* no trailing null to account for in value len */ within the SMB BB*/
/* no trailing null to account for
in value len */
/* go on to next EA */ /* go on to next EA */
temp_fea = (struct fea *)temp_ptr; temp_fea = (struct fea *)temp_ptr;
} }
@ -5274,7 +5383,7 @@ QEARetry:
struct fealist *ea_response_data; struct fealist *ea_response_data;
rc = -ENODATA; rc = -ENODATA;
/* validate_trans2_offsets() */ /* validate_trans2_offsets() */
/* BB to check if(start of smb + data_offset > &bcc+ bcc)*/ /* BB check if start of smb + data_offset > &bcc+ bcc*/
ea_response_data = (struct fealist *) ea_response_data = (struct fealist *)
(((char *) &pSMBr->hdr.Protocol) + (((char *) &pSMBr->hdr.Protocol) +
data_offset); data_offset);
@ -5294,7 +5403,8 @@ QEARetry:
__u16 value_len; __u16 value_len;
name_len -= 4; name_len -= 4;
temp_ptr += 4; temp_ptr += 4;
value_len = le16_to_cpu(temp_fea->value_len); value_len =
le16_to_cpu(temp_fea->value_len);
/* BB validate that value_len falls within SMB, /* BB validate that value_len falls within SMB,
even though maximum for name_len is 255 */ even though maximum for name_len is 255 */
if (memcmp(temp_fea->name, ea_name, if (memcmp(temp_fea->name, ea_name,
@ -5306,8 +5416,9 @@ QEARetry:
memcpy(ea_value, memcpy(ea_value,
temp_fea->name+temp_fea->name_len+1, temp_fea->name+temp_fea->name_len+1,
rc); rc);
/* ea values, unlike ea names, /* ea values, unlike ea
are not null terminated */ names, are not null
terminated */
} else if (buf_size == 0) { } else if (buf_size == 0) {
/* skip copy - calc size only */ /* skip copy - calc size only */
} else { } else {
@ -5323,8 +5434,8 @@ QEARetry:
temp_ptr++; temp_ptr++;
name_len -= value_len; name_len -= value_len;
temp_ptr += value_len; temp_ptr += value_len;
/* no trailing null to account for in value len */ /* No trailing null to account for in
/* go on to next EA */ value_len. Go on to next EA */
temp_fea = (struct fea *)temp_ptr; temp_fea = (struct fea *)temp_ptr;
} }
} }
@ -5417,10 +5528,12 @@ SetEARetry:
/* caller ensures that ea_value_len is less than 64K but /* caller ensures that ea_value_len is less than 64K but
we need to ensure that it fits within the smb */ we need to ensure that it fits within the smb */
/*BB add length check that it would fit in negotiated SMB buffer size BB */ /*BB add length check to see if it would fit in
negotiated SMB buffer size BB */
/* if (ea_value_len > buffer_size - 512 (enough for header)) */ /* if (ea_value_len > buffer_size - 512 (enough for header)) */
if (ea_value_len) if (ea_value_len)
memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len); memcpy(parm_data->list[0].name+name_len+1,
ea_value, ea_value_len);
pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalDataCount = pSMB->DataCount;
pSMB->ParameterCount = cpu_to_le16(params); pSMB->ParameterCount = cpu_to_le16(params);

View file

@ -1,7 +1,7 @@
/* /*
* fs/cifs/connect.c * fs/cifs/connect.c
* *
* Copyright (C) International Business Machines Corp., 2002,2006 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
@ -85,6 +85,7 @@ struct smb_vol {
unsigned direct_io:1; unsigned direct_io:1;
unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned remap:1; /* set to remap seven reserved chars in filenames */
unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
unsigned no_linux_ext:1;
unsigned sfu_emul:1; unsigned sfu_emul:1;
unsigned nullauth:1; /* attempt to authenticate with null user */ unsigned nullauth:1; /* attempt to authenticate with null user */
unsigned nocase; /* request case insensitive filenames */ unsigned nocase; /* request case insensitive filenames */
@ -161,7 +162,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state, cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
server->ssocket->flags)); server->ssocket->flags));
server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN); server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);
cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state, cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
server->ssocket->state,
server->ssocket->flags)); server->ssocket->flags));
sock_release(server->ssocket); sock_release(server->ssocket);
server->ssocket = NULL; server->ssocket = NULL;
@ -185,11 +187,11 @@ cifs_reconnect(struct TCP_Server_Info *server)
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
up(&server->tcpSem); up(&server->tcpSem);
while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood)) while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
{
try_to_freeze(); try_to_freeze();
if (server->protocolType == IPV6) { if (server->protocolType == IPV6) {
rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); rc = ipv6_connect(&server->addr.sockAddr6,
&server->ssocket);
} else { } else {
rc = ipv4_connect(&server->addr.sockAddr, rc = ipv4_connect(&server->addr.sockAddr,
&server->ssocket, &server->ssocket,
@ -277,7 +279,7 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
cFYI(1,("total data sizes of primary and secondary t2 differ")); cFYI(1, ("total data size of primary and secondary t2 differ"));
} }
total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
@ -348,7 +350,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
int isMultiRsp; int isMultiRsp;
int reconnect; int reconnect;
allow_signal(SIGKILL);
current->flags |= PF_MEMALLOC; current->flags |= PF_MEMALLOC;
server->tsk = current; /* save process info to wake at shutdown */ server->tsk = current; /* save process info to wake at shutdown */
cFYI(1, ("Demultiplex PID: %d", current->pid)); cFYI(1, ("Demultiplex PID: %d", current->pid));
@ -459,7 +460,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
pdu_length = ntohl(smb_buffer->smb_buf_length); pdu_length = ntohl(smb_buffer->smb_buf_length);
smb_buffer->smb_buf_length = pdu_length; smb_buffer->smb_buf_length = pdu_length;
cFYI(1,("rfc1002 length 0x%x)", pdu_length+4)); cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) { if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
continue; continue;
@ -638,7 +639,8 @@ multi_t2_fnd:
wake_up_process(task_to_wake); wake_up_process(task_to_wake);
} else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
&& (isMultiRsp == FALSE)) { && (isMultiRsp == FALSE)) {
cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter)); cERROR(1, ("No task to wake, unknown frame received! "
"NumMids %d", midCount.counter));
cifs_dump_mem("Received Data is: ", (char *)smb_buffer, cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
sizeof(struct smb_hdr)); sizeof(struct smb_hdr));
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
@ -709,8 +711,8 @@ multi_t2_fnd:
list_for_each(tmp, &server->pending_mid_q) { list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead); mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if (mid_entry->midState == MID_REQUEST_SUBMITTED) { if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
cFYI(1, cFYI(1, ("Clearing Mid 0x%x - waking up ",
("Clearing Mid 0x%x - waking up ",mid_entry->mid)); mid_entry->mid));
task_to_wake = mid_entry->tsk; task_to_wake = mid_entry->tsk;
if (task_to_wake) { if (task_to_wake) {
wake_up_process(task_to_wake); wake_up_process(task_to_wake);
@ -764,7 +766,8 @@ multi_t2_fnd:
} }
static int static int
cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) cifs_parse_mount_options(char *options, const char *devname,
struct smb_vol *vol)
{ {
char *value; char *value;
char *data; char *data;
@ -820,7 +823,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
if ((value = strchr(data, '=')) != NULL) if ((value = strchr(data, '=')) != NULL)
*value++ = '\0'; *value++ = '\0';
if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/ /* Have to parse this before we parse for "user" */
if (strnicmp(data, "user_xattr", 10) == 0) {
vol->no_xattr = 0; vol->no_xattr = 0;
} else if (strnicmp(data, "nouser_xattr", 12) == 0) { } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
vol->no_xattr = 1; vol->no_xattr = 1;
@ -871,7 +875,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
(value[temp_len+1] == separator[0])) { (value[temp_len+1] == separator[0])) {
/* reinsert comma */ /* reinsert comma */
value[temp_len] = separator[0]; value[temp_len] = separator[0];
temp_len+=2; /* move after the second comma */ temp_len += 2; /* move after second comma */
while (value[temp_len] != 0) { while (value[temp_len] != 0) {
if (value[temp_len] == separator[0]) { if (value[temp_len] == separator[0]) {
if (value[temp_len+1] == if (value[temp_len+1] ==
@ -898,7 +902,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
allocating a few bytes too many, which is ok */ allocating a few bytes too many, which is ok */
vol->password = kzalloc(temp_len, GFP_KERNEL); vol->password = kzalloc(temp_len, GFP_KERNEL);
if (vol->password == NULL) { if (vol->password == NULL) {
printk("CIFS: no memory for pass\n"); printk(KERN_WARNING "CIFS: no memory "
"for password\n");
return 1; return 1;
} }
for (i = 0, j = 0; i < temp_len; i++, j++) { for (i = 0, j = 0; i < temp_len; i++, j++) {
@ -913,7 +918,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} else { } else {
vol->password = kzalloc(temp_len+1, GFP_KERNEL); vol->password = kzalloc(temp_len+1, GFP_KERNEL);
if (vol->password == NULL) { if (vol->password == NULL) {
printk("CIFS: no memory for pass\n"); printk(KERN_WARNING "CIFS: no memory "
"for password\n");
return 1; return 1;
} }
strcpy(vol->password, value); strcpy(vol->password, value);
@ -924,7 +930,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} else if (strnlen(value, 35) < 35) { } else if (strnlen(value, 35) < 35) {
vol->UNCip = value; vol->UNCip = value;
} else { } else {
printk(KERN_WARNING "CIFS: ip address too long\n"); printk(KERN_WARNING "CIFS: ip address "
"too long\n");
return 1; return 1;
} }
} else if (strnicmp(data, "sec", 3) == 0) { } else if (strnicmp(data, "sec", 3) == 0) {
@ -969,8 +976,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|| (strnicmp(data, "target", 6) == 0) || (strnicmp(data, "target", 6) == 0)
|| (strnicmp(data, "path", 4) == 0)) { || (strnicmp(data, "path", 4) == 0)) {
if (!value || !*value) { if (!value || !*value) {
printk(KERN_WARNING printk(KERN_WARNING "CIFS: invalid path to "
"CIFS: invalid path to network resource\n"); "network resource\n");
return 1; /* needs_arg; */ return 1; /* needs_arg; */
} }
if ((temp_len = strnlen(value, 300)) < 300) { if ((temp_len = strnlen(value, 300)) < 300) {
@ -983,7 +990,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->UNC[1] = '\\'; vol->UNC[1] = '\\';
} else if (strncmp(vol->UNC, "\\\\", 2) != 0) { } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
printk(KERN_WARNING printk(KERN_WARNING
"CIFS: UNC Path does not begin with // or \\\\ \n"); "CIFS: UNC Path does not begin "
"with // or \\\\ \n");
return 1; return 1;
} }
} else { } else {
@ -1002,14 +1010,15 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->domainname = value; vol->domainname = value;
cFYI(1, ("Domain name set")); cFYI(1, ("Domain name set"));
} else { } else {
printk(KERN_WARNING "CIFS: domain name too long\n"); printk(KERN_WARNING "CIFS: domain name too "
"long\n");
return 1; return 1;
} }
} else if (strnicmp(data, "prefixpath", 10) == 0) { } else if (strnicmp(data, "prefixpath", 10) == 0) {
if (!value || !*value) { if (!value || !*value) {
printk(KERN_WARNING printk(KERN_WARNING
"CIFS: invalid path prefix\n"); "CIFS: invalid path prefix\n");
return 1; /* needs_arg; */ return 1; /* needs_argument */
} }
if ((temp_len = strnlen(value, 1024)) < 1024) { if ((temp_len = strnlen(value, 1024)) < 1024) {
if (value[0] != '/') if (value[0] != '/')
@ -1029,16 +1038,19 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} }
} else if (strnicmp(data, "iocharset", 9) == 0) { } else if (strnicmp(data, "iocharset", 9) == 0) {
if (!value || !*value) { if (!value || !*value) {
printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); printk(KERN_WARNING "CIFS: invalid iocharset "
"specified\n");
return 1; /* needs_arg; */ return 1; /* needs_arg; */
} }
if (strnlen(value, 65) < 65) { if (strnlen(value, 65) < 65) {
if (strnicmp(value, "default", 7)) if (strnicmp(value, "default", 7))
vol->iocharset = value; vol->iocharset = value;
/* if iocharset not set load_nls_default used by caller */ /* if iocharset not set then load_nls_default
is used by caller */
cFYI(1, ("iocharset set to %s", value)); cFYI(1, ("iocharset set to %s", value));
} else { } else {
printk(KERN_WARNING "CIFS: iocharset name too long.\n"); printk(KERN_WARNING "CIFS: iocharset name "
"too long.\n");
return 1; return 1;
} }
} else if (strnicmp(data, "uid", 3) == 0) { } else if (strnicmp(data, "uid", 3) == 0) {
@ -1090,7 +1102,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} }
} else if (strnicmp(data, "netbiosname", 4) == 0) { } else if (strnicmp(data, "netbiosname", 4) == 0) {
if (!value || !*value || (*value == ' ')) { if (!value || !*value || (*value == ' ')) {
cFYI(1,("invalid (empty) netbiosname specified")); cFYI(1, ("invalid (empty) netbiosname"));
} else { } else {
memset(vol->source_rfc1001_name, 0x20, 15); memset(vol->source_rfc1001_name, 0x20, 15);
for (i = 0; i < 15; i++) { for (i = 0; i < 15; i++) {
@ -1102,12 +1114,14 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
if (value[i] == 0) if (value[i] == 0)
break; break;
else else
vol->source_rfc1001_name[i] = value[i]; vol->source_rfc1001_name[i] =
value[i];
} }
/* The string has 16th byte zero still from /* The string has 16th byte zero still from
set at top of the function */ set at top of the function */
if ((i == 15) && (value[i] != 0)) if ((i == 15) && (value[i] != 0))
printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n"); printk(KERN_WARNING "CIFS: netbiosname"
" longer than 15 truncated.\n");
} }
} else if (strnicmp(data, "servern", 7) == 0) { } else if (strnicmp(data, "servern", 7) == 0) {
/* servernetbiosname specified override *SMBSERVER */ /* servernetbiosname specified override *SMBSERVER */
@ -1119,19 +1133,22 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
for (i = 0; i < 15; i++) { for (i = 0; i < 15; i++) {
/* BB are there cases in which a comma can be /* BB are there cases in which a comma can be
valid in this workstation netbios name (and need valid in this workstation netbios name
special handling)? */ (and need special handling)? */
/* user or mount helper must uppercase netbiosname */ /* user or mount helper must uppercase
the netbiosname */
if (value[i] == 0) if (value[i] == 0)
break; break;
else else
vol->target_rfc1001_name[i] = value[i]; vol->target_rfc1001_name[i] =
value[i];
} }
/* The string has 16th byte zero still from /* The string has 16th byte zero still from
set at top of the function */ set at top of the function */
if ((i == 15) && (value[i] != 0)) if ((i == 15) && (value[i] != 0))
printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n"); printk(KERN_WARNING "CIFS: server net"
"biosname longer than 15 truncated.\n");
} }
} else if (strnicmp(data, "credentials", 4) == 0) { } else if (strnicmp(data, "credentials", 4) == 0) {
/* ignore */ /* ignore */
@ -1177,6 +1194,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->posix_paths = 1; vol->posix_paths = 1;
} else if (strnicmp(data, "noposixpaths", 12) == 0) { } else if (strnicmp(data, "noposixpaths", 12) == 0) {
vol->posix_paths = 0; vol->posix_paths = 0;
} else if (strnicmp(data, "nounix", 6) == 0) {
vol->no_linux_ext = 1;
} else if (strnicmp(data, "nolinux", 7) == 0) {
vol->no_linux_ext = 1;
} else if ((strnicmp(data, "nocase", 6) == 0) || } else if ((strnicmp(data, "nocase", 6) == 0) ||
(strnicmp(data, "ignorecase", 10) == 0)) { (strnicmp(data, "ignorecase", 10) == 0)) {
vol->nocase = 1; vol->nocase = 1;
@ -1188,7 +1209,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* turn off mandatory locking in mode /* turn off mandatory locking in mode
if remote locking is turned off since the if remote locking is turned off since the
local vfs will do advisory */ local vfs will do advisory */
if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP))) if (vol->file_mode ==
(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
vol->file_mode = S_IALLUGO; vol->file_mode = S_IALLUGO;
} else if (strnicmp(data, "setuids", 7) == 0) { } else if (strnicmp(data, "setuids", 7) == 0) {
vol->setuids = 1; vol->setuids = 1;
@ -1228,17 +1250,22 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} else if (strnlen(value, 49) == 48) { } else if (strnlen(value, 49) == 48) {
vol->in6_addr = value; vol->in6_addr = value;
} else { } else {
printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n"); printk(KERN_WARNING "CIFS: ip v6 address not "
"48 characters long\n");
return 1; return 1;
} }
} else if (strnicmp(data, "noac", 4) == 0) { } else if (strnicmp(data, "noac", 4) == 0) {
printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); printk(KERN_WARNING "CIFS: Mount option noac not "
"supported. Instead set "
"/proc/fs/cifs/LookupCacheEnabled to 0\n");
} else } else
printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
data);
} }
if (vol->UNC == NULL) { if (vol->UNC == NULL) {
if (devname == NULL) { if (devname == NULL) {
printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); printk(KERN_WARNING "CIFS: Missing UNC name for mount "
"target\n");
return 1; return 1;
} }
if ((temp_len = strnlen(devname, 300)) < 300) { if ((temp_len = strnlen(devname, 300)) < 300) {
@ -1250,7 +1277,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->UNC[0] = '\\'; vol->UNC[0] = '\\';
vol->UNC[1] = '\\'; vol->UNC[1] = '\\';
} else if (strncmp(vol->UNC, "\\\\", 2) != 0) { } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n"); printk(KERN_WARNING "CIFS: UNC Path does not "
"begin with // or \\\\ \n");
return 1; return 1;
} }
} else { } else {
@ -1282,14 +1310,20 @@ cifs_find_tcp_session(struct in_addr * target_ip_addr,
== target_ip_addr->s_addr)) || (target_ip6_addr == target_ip_addr->s_addr)) || (target_ip6_addr
&& memcmp(&ses->server->addr.sockAddr6.sin6_addr, && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
target_ip6_addr, sizeof(*target_ip6_addr)))) { target_ip6_addr, sizeof(*target_ip6_addr)))) {
/* BB lock server and tcp session and increment use count here?? */ /* BB lock server and tcp session and increment
*psrvTcp = ses->server; /* found a match on the TCP session */ use count here?? */
/* found a match on the TCP session */
*psrvTcp = ses->server;
/* BB check if reconnection needed */ /* BB check if reconnection needed */
if (strncmp if (strncmp
(ses->userName, userName, (ses->userName, userName,
MAX_USERNAME_SIZE) == 0){ MAX_USERNAME_SIZE) == 0){
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
return ses; /* found exact match on both tcp and SMB sessions */ /* Found exact match on both TCP and
SMB sessions */
return ses;
} }
} }
} }
@ -1320,7 +1354,8 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
/* BB lock tcon, server and tcp session and increment use count here? */ /* BB lock tcon, server and tcp session and increment use count here? */
/* found a match on the TCP session */ /* found a match on the TCP session */
/* BB check if reconnection needed */ /* BB check if reconnection needed */
cFYI(1,("IP match, old UNC: %s new: %s", cFYI(1,
("IP match, old UNC: %s new: %s",
tcon->treeName, uncName)); tcon->treeName, uncName));
if (strncmp if (strncmp
(tcon->treeName, uncName, (tcon->treeName, uncName,
@ -1368,9 +1403,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
} }
int int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
const char *old_path, const struct nls_table *nls_codepage, const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
unsigned int *pnum_referrals,
unsigned char **preferrals, int remap) unsigned char **preferrals, int remap)
{ {
char *temp_unc; char *temp_unc;
@ -1380,7 +1414,8 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
if (pSesInfo->ipc_tid == 0) { if (pSesInfo->ipc_tid == 0) {
temp_unc = kmalloc(2 /* for slashes */ + temp_unc = kmalloc(2 /* for slashes */ +
strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2) strnlen(pSesInfo->serverName,
SERVER_NAME_LEN_WITH_NULL * 2)
+ 1 + 4 /* slash IPC$ */ + 2, + 1 + 4 /* slash IPC$ */ + 2,
GFP_KERNEL); GFP_KERNEL);
if (temp_unc == NULL) if (temp_unc == NULL)
@ -1425,7 +1460,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
__be16 orig_port = 0; __be16 orig_port = 0;
if (*csocket == NULL) { if (*csocket == NULL) {
rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); rc = sock_create_kern(PF_INET, SOCK_STREAM,
IPPROTO_TCP, csocket);
if (rc < 0) { if (rc < 0) {
cERROR(1, ("Error %d creating socket", rc)); cERROR(1, ("Error %d creating socket", rc));
*csocket = NULL; *csocket = NULL;
@ -1465,7 +1501,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
if (!connected) { if (!connected) {
psin_server->sin_port = htons(RFC1001_PORT); psin_server->sin_port = htons(RFC1001_PORT);
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
psin_server, sizeof (struct sockaddr_in),0); psin_server,
sizeof (struct sockaddr_in), 0);
if (rc >= 0) if (rc >= 0)
connected = 1; connected = 1;
} }
@ -1483,7 +1520,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
/* Eventually check for other socket options to change from /* Eventually check for other socket options to change from
the default. sock_setsockopt not used because it expects the default. sock_setsockopt not used because it expects
user space buffer */ user space buffer */
cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf, cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
(*csocket)->sk->sk_sndbuf,
(*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
(*csocket)->sk->sk_rcvtimeo = 7 * HZ; (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
/* make the bufsizes depend on wsize/rsize and max requests */ /* make the bufsizes depend on wsize/rsize and max requests */
@ -1499,7 +1537,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
sessinit is sent but no second negprot */ sessinit is sent but no second negprot */
struct rfc1002_session_packet *ses_init_buf; struct rfc1002_session_packet *ses_init_buf;
struct smb_hdr *smb_buf; struct smb_hdr *smb_buf;
ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
GFP_KERNEL);
if (ses_init_buf) { if (ses_init_buf) {
ses_init_buf->trailer.session_req.called_len = 32; ses_init_buf->trailer.session_req.called_len = 32;
if (target_name && (target_name[0] != 0)) { if (target_name && (target_name[0] != 0)) {
@ -1553,7 +1592,8 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
__be16 orig_port = 0; __be16 orig_port = 0;
if (*csocket == NULL) { if (*csocket == NULL) {
rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); rc = sock_create_kern(PF_INET6, SOCK_STREAM,
IPPROTO_TCP, csocket);
if (rc < 0) { if (rc < 0) {
cERROR(1, ("Error %d creating ipv6 socket", rc)); cERROR(1, ("Error %d creating ipv6 socket", rc));
*csocket = NULL; *csocket = NULL;
@ -1631,6 +1671,18 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
* and once without posixacls or posix paths? */ * and once without posixacls or posix paths? */
__u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
if (vol_info && vol_info->no_linux_ext) {
tcon->fsUnixInfo.Capability = 0;
tcon->unix_ext = 0; /* Unix Extensions disabled */
cFYI(1, ("Linux protocol extensions disabled"));
return;
} else if (vol_info)
tcon->unix_ext = 1; /* Unix Extensions supported */
if (tcon->unix_ext == 0) {
cFYI(1, ("Unix extensions disabled so not set on reconnect"));
return;
}
if (!CIFSSMBQFSUnixInfo(xid, tcon)) { if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
__u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
@ -1644,10 +1696,6 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
cap &= ~CIFS_UNIX_POSIX_ACL_CAP; cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
} }
cap &= CIFS_UNIX_CAP_MASK; cap &= CIFS_UNIX_CAP_MASK;
@ -1674,6 +1722,16 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
if (sb && (CIFS_SB(sb)->prepathlen > 0)) if (sb && (CIFS_SB(sb)->prepathlen > 0))
CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb)); CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
CIFS_SB(sb)->rsize = 127 * 1024;
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("larger reads not supported by srv"));
#endif
}
}
cFYI(1, ("Negotiate caps 0x%x", (int)cap)); cFYI(1, ("Negotiate caps 0x%x", (int)cap));
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
if (cap & CIFS_UNIX_FCNTL_CAP) if (cap & CIFS_UNIX_FCNTL_CAP)
@ -1686,6 +1744,10 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
cFYI(1, ("XATTR cap")); cFYI(1, ("XATTR cap"));
if (cap & CIFS_UNIX_POSIX_ACL_CAP) if (cap & CIFS_UNIX_POSIX_ACL_CAP)
cFYI(1, ("POSIX ACL cap")); cFYI(1, ("POSIX ACL cap"));
if (cap & CIFS_UNIX_LARGE_READ_CAP)
cFYI(1, ("very large read cap"));
if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
cFYI(1, ("very large write cap"));
#endif /* CIFS_DEBUG2 */ #endif /* CIFS_DEBUG2 */
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
cFYI(1, ("setting capabilities failed")); cFYI(1, ("setting capabilities failed"));
@ -1740,11 +1802,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} }
if (volume_info.UNCip && volume_info.UNC) { if (volume_info.UNCip && volume_info.UNC) {
rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
&sin_server.sin_addr.s_addr);
if (rc <= 0) { if (rc <= 0) {
/* not ipv4 address, try ipv6 */ /* not ipv4 address, try ipv6 */
rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
&sin_server6.sin6_addr.in6_u);
if (rc > 0) if (rc > 0)
address_type = AF_INET6; address_type = AF_INET6;
} else { } else {
@ -1764,7 +1828,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* success */ /* success */
rc = 0; rc = 0;
} else if (volume_info.UNCip) { } else if (volume_info.UNCip) {
/* BB using ip addr as server name connect to the DFS root below */ /* BB using ip addr as server name to connect to the
DFS root below */
cERROR(1, ("Connecting to DFS root not implemented yet")); cERROR(1, ("Connecting to DFS root not implemented yet"));
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
@ -1773,7 +1838,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return -EINVAL; return -EINVAL;
} else /* which servers DFS root would we conect to */ { } else /* which servers DFS root would we conect to */ {
cERROR(1, cERROR(1,
("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified")); ("CIFS mount error: No UNC path (e.g. -o "
"unc=//192.168.1.100/public) specified"));
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
kfree(volume_info.prepath); kfree(volume_info.prepath);
@ -1788,7 +1854,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} else { } else {
cifs_sb->local_nls = load_nls(volume_info.iocharset); cifs_sb->local_nls = load_nls(volume_info.iocharset);
if (cifs_sb->local_nls == NULL) { if (cifs_sb->local_nls == NULL) {
cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); cERROR(1, ("CIFS mount error: iocharset %s not found",
volume_info.iocharset));
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
kfree(volume_info.prepath); kfree(volume_info.prepath);
@ -1814,7 +1881,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return -EINVAL; return -EINVAL;
} }
if (srvTcp) { if (srvTcp) {
cFYI(1, ("Existing tcp session with server found")); cFYI(1, ("Existing tcp session with server found"));
} else { /* create socket */ } else { /* create socket */
@ -1832,8 +1898,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
volume_info.source_rfc1001_name, volume_info.source_rfc1001_name,
volume_info.target_rfc1001_name); volume_info.target_rfc1001_name);
if (rc < 0) { if (rc < 0) {
cERROR(1, cERROR(1, ("Error connecting to IPv4 socket. "
("Error connecting to IPv4 socket. Aborting operation")); "Aborting operation"));
if (csocket != NULL) if (csocket != NULL)
sock_release(csocket); sock_release(csocket);
kfree(volume_info.UNC); kfree(volume_info.UNC);
@ -1854,7 +1920,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return rc; return rc;
} else { } else {
memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); memcpy(&srvTcp->addr.sockAddr, &sin_server,
sizeof (struct sockaddr_in));
atomic_set(&srvTcp->inFlight, 0); atomic_set(&srvTcp->inFlight, 0);
/* BB Add code for ipv6 case too */ /* BB Add code for ipv6 case too */
srvTcp->ssocket = csocket; srvTcp->ssocket = csocket;
@ -1881,8 +1948,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} }
wait_for_completion(&cifsd_complete); wait_for_completion(&cifsd_complete);
rc = 0; rc = 0;
memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); memcpy(srvTcp->workstation_RFC1001_name,
memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16); volume_info.source_rfc1001_name, 16);
memcpy(srvTcp->server_RFC1001_name,
volume_info.target_rfc1001_name, 16);
srvTcp->sequence_number = 0; srvTcp->sequence_number = 0;
} }
} }
@ -1909,7 +1978,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
pSesInfo->password = volume_info.password; pSesInfo->password = volume_info.password;
if (volume_info.username) if (volume_info.username)
strncpy(pSesInfo->userName, strncpy(pSesInfo->userName,
volume_info.username,MAX_USERNAME_SIZE); volume_info.username,
MAX_USERNAME_SIZE);
if (volume_info.domainname) { if (volume_info.domainname) {
int len = strlen(volume_info.domainname); int len = strlen(volume_info.domainname);
pSesInfo->domainName = pSesInfo->domainName =
@ -1922,7 +1992,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
pSesInfo->overrideSecFlg = volume_info.secFlg; pSesInfo->overrideSecFlg = volume_info.secFlg;
down(&pSesInfo->sesSem); down(&pSesInfo->sesSem);
/* BB FIXME need to pass vol->secFlgs BB */ /* BB FIXME need to pass vol->secFlgs BB */
rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); rc = cifs_setup_session(xid, pSesInfo,
cifs_sb->local_nls);
up(&pSesInfo->sesSem); up(&pSesInfo->sesSem);
if (!rc) if (!rc)
atomic_inc(&srvTcp->socketUseCount); atomic_inc(&srvTcp->socketUseCount);
@ -1936,13 +2007,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cERROR(1, ("rsize %d too large, using MaxBufSize", cERROR(1, ("rsize %d too large, using MaxBufSize",
volume_info.rsize)); volume_info.rsize));
cifs_sb->rsize = CIFSMaxBufSize; cifs_sb->rsize = CIFSMaxBufSize;
} else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) } else if ((volume_info.rsize) &&
(volume_info.rsize <= CIFSMaxBufSize))
cifs_sb->rsize = volume_info.rsize; cifs_sb->rsize = volume_info.rsize;
else /* default */ else /* default */
cifs_sb->rsize = CIFSMaxBufSize; cifs_sb->rsize = CIFSMaxBufSize;
if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
cERROR(1,("wsize %d too large using 4096 instead", cERROR(1, ("wsize %d too large, using 4096 instead",
volume_info.wsize)); volume_info.wsize));
cifs_sb->wsize = 4096; cifs_sb->wsize = 4096;
} else if (volume_info.wsize) } else if (volume_info.wsize)
@ -1961,7 +2033,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (cifs_sb->rsize < 2048) { if (cifs_sb->rsize < 2048) {
cifs_sb->rsize = 2048; cifs_sb->rsize = 2048;
/* Windows ME may prefer this */ /* Windows ME may prefer this */
cFYI(1,("readsize set to minimum 2048")); cFYI(1, ("readsize set to minimum: 2048"));
} }
/* calculate prepath */ /* calculate prepath */
cifs_sb->prepath = volume_info.prepath; cifs_sb->prepath = volume_info.prepath;
@ -2075,7 +2147,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
always wake up processes blocked in always wake up processes blocked in
tcp in recv_mesg then we could remove the tcp in recv_mesg then we could remove the
send_sig call */ send_sig call */
send_sig(SIGKILL,srvTcp->tsk,1); force_sig(SIGKILL, srvTcp->tsk);
tsk = srvTcp->tsk; tsk = srvTcp->tsk;
if (tsk) if (tsk)
kthread_stop(tsk); kthread_stop(tsk);
@ -2092,9 +2164,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
temp_rc = CIFSSMBLogoff(xid, pSesInfo); temp_rc = CIFSSMBLogoff(xid, pSesInfo);
/* if the socketUseCount is now zero */ /* if the socketUseCount is now zero */
if ((temp_rc == -ESHUTDOWN) && if ((temp_rc == -ESHUTDOWN) &&
(pSesInfo->server) && (pSesInfo->server->tsk)) { (pSesInfo->server) &&
(pSesInfo->server->tsk)) {
struct task_struct *tsk; struct task_struct *tsk;
send_sig(SIGKILL,pSesInfo->server->tsk,1); force_sig(SIGKILL,
pSesInfo->server->tsk);
tsk = pSesInfo->server->tsk; tsk = pSesInfo->server->tsk;
if (tsk) if (tsk)
kthread_stop(tsk); kthread_stop(tsk);
@ -2116,8 +2190,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* tell server which Unix caps we support */ /* tell server which Unix caps we support */
if (tcon->ses->capabilities & CAP_UNIX) if (tcon->ses->capabilities & CAP_UNIX)
/* reset of caps checks mount to see if unix extensions
disabled for just this mount */
reset_cifs_unix_caps(xid, tcon, sb, &volume_info); reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
else
tcon->unix_ext = 0; /* server does not support them */
if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
cifs_sb->rsize = 1024 * 127;
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("no very large read support, rsize now 127K"));
#endif
}
if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
cifs_sb->wsize = min(cifs_sb->wsize, cifs_sb->wsize = min(cifs_sb->wsize,
(tcon->ses->server->maxBuf - (tcon->ses->server->maxBuf -
@ -2178,7 +2262,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
@ -2282,8 +2367,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 action = le16_to_cpu(pSMBr->resp.Action);
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN) if (action & GUEST_LOGIN)
cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */ cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
(little endian) */
cFYI(1, ("UID = %d ", ses->Suid)); cFYI(1, ("UID = %d ", ses->Suid));
/* response can have either 3 or 4 word count - Samba sends 3 */ /* response can have either 3 or 4 word count - Samba sends 3 */
bcc_ptr = pByteArea(smb_buffer_response); bcc_ptr = pByteArea(smb_buffer_response);
@ -2297,7 +2383,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if ((long) (bcc_ptr) % 2) { if ((long) (bcc_ptr) % 2) {
remaining_words = remaining_words =
(BCC(smb_buffer_response) - 1) / 2; (BCC(smb_buffer_response) - 1) / 2;
bcc_ptr++; /* Unicode strings must be word aligned */ /* Unicode strings must be word
aligned */
bcc_ptr++;
} else { } else {
remaining_words = remaining_words =
BCC(smb_buffer_response) / 2; BCC(smb_buffer_response) / 2;
@ -2310,11 +2398,13 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
terminating last Unicode string in response */ terminating last Unicode string in response */
if (ses->serverOS) if (ses->serverOS)
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); ses->serverOS = kzalloc(2 * (len + 1),
GFP_KERNEL);
if (ses->serverOS == NULL) if (ses->serverOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverOS, cifs_strfromUCS_le(ses->serverOS,
(__le16 *)bcc_ptr, len,nls_codepage); (__le16 *)bcc_ptr,
len, nls_codepage);
bcc_ptr += 2 * (len + 1); bcc_ptr += 2 * (len + 1);
remaining_words -= len + 1; remaining_words -= len + 1;
ses->serverOS[2 * len] = 0; ses->serverOS[2 * len] = 0;
@ -2323,11 +2413,13 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = UniStrnlen((wchar_t *)bcc_ptr, len = UniStrnlen((wchar_t *)bcc_ptr,
remaining_words-1); remaining_words-1);
kfree(ses->serverNOS); kfree(ses->serverNOS);
ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL); ses->serverNOS = kzalloc(2 * (len + 1),
GFP_KERNEL);
if (ses->serverNOS == NULL) if (ses->serverNOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverNOS, cifs_strfromUCS_le(ses->serverNOS,
(__le16 *)bcc_ptr,len,nls_codepage); (__le16 *)bcc_ptr,
len, nls_codepage);
bcc_ptr += 2 * (len + 1); bcc_ptr += 2 * (len + 1);
ses->serverNOS[2 * len] = 0; ses->serverNOS[2 * len] = 0;
ses->serverNOS[1 + (2 * len)] = 0; ses->serverNOS[1 + (2 * len)] = 0;
@ -2339,26 +2431,31 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
remaining_words -= len + 1; remaining_words -= len + 1;
if (remaining_words > 0) { if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */ /* last string is not always null terminated
(for e.g. for Windows XP & 2000) */
if (ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2*(len+1),GFP_KERNEL); kzalloc(2*(len+1),
GFP_KERNEL);
if (ses->serverDomain == NULL) if (ses->serverDomain == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverDomain, cifs_strfromUCS_le(ses->serverDomain,
(__le16 *)bcc_ptr,len,nls_codepage); (__le16 *)bcc_ptr,
len, nls_codepage);
bcc_ptr += 2 * (len + 1); bcc_ptr += 2 * (len + 1);
ses->serverDomain[2*len] = 0; ses->serverDomain[2*len] = 0;
ses->serverDomain[1+(2*len)] = 0; ses->serverDomain[1+(2*len)] = 0;
} /* else no more room so create dummy domain string */ } else { /* else no more room so create
else { dummy domain string */
if (ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2, GFP_KERNEL); kzalloc(2, GFP_KERNEL);
} }
} else { /* no room so create dummy domain and NOS string */ } else { /* no room so create dummy domain
and NOS string */
/* if these kcallocs fail not much we /* if these kcallocs fail not much we
can do, but better to not fail the can do, but better to not fail the
sesssetup itself */ sesssetup itself */
@ -2375,18 +2472,21 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pByteArea(smb_buffer_response) pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) { <= BCC(smb_buffer_response)) {
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = kzalloc(len + 1,GFP_KERNEL); ses->serverOS = kzalloc(len + 1,
GFP_KERNEL);
if (ses->serverOS == NULL) if (ses->serverOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
strncpy(ses->serverOS, bcc_ptr, len); strncpy(ses->serverOS, bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; /* null terminate the string */ /* null terminate the string */
bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
kfree(ses->serverNOS); kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); ses->serverNOS = kzalloc(len + 1,
GFP_KERNEL);
if (ses->serverNOS == NULL) if (ses->serverNOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
strncpy(ses->serverNOS, bcc_ptr, len); strncpy(ses->serverNOS, bcc_ptr, len);
@ -2397,21 +2497,25 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
if (ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = kzalloc(len + 1,GFP_KERNEL); ses->serverDomain = kzalloc(len + 1,
GFP_KERNEL);
if (ses->serverDomain == NULL) if (ses->serverDomain == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
strncpy(ses->serverDomain, bcc_ptr, len); strncpy(ses->serverDomain, bcc_ptr,
len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
} else } else
cFYI(1, cFYI(1,
("Variable field of length %d extends beyond end of smb ", ("Variable field of length %d "
"extends beyond end of smb ",
len)); len));
} }
} else { } else {
cERROR(1, cERROR(1,
(" Security Blob Length extends beyond end of SMB")); (" Security Blob Length extends beyond "
"end of SMB"));
} }
} else { } else {
cERROR(1, cERROR(1,
@ -2623,7 +2727,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
remaining_words = remaining_words =
(BCC(smb_buffer_response) (BCC(smb_buffer_response)
- 1) / 2; - 1) / 2;
bcc_ptr++; /* Unicode strings must be word aligned */ /* Must word align unicode strings */
bcc_ptr++;
} else { } else {
remaining_words = remaining_words =
BCC BCC
@ -2669,7 +2774,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
remaining_words -= len + 1; remaining_words -= len + 1;
if (remaining_words > 0) { if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */ /* last string not always null terminated
(for e.g. for Windows XP & 2000) */
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2 * kzalloc(2 *
@ -2734,18 +2840,20 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
ses->serverDomain = ses->serverDomain =
kzalloc(len + 1, kzalloc(len + 1,
GFP_KERNEL); GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len); strncpy(ses->serverDomain,
bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
} else } else
cFYI(1, cFYI(1,
("Variable field of length %d extends beyond end of smb", ("field of length %d "
"extends beyond end of smb",
len)); len));
} }
} else { } else {
cERROR(1, cERROR(1, ("Security Blob Length extends beyond"
(" Security Blob Length extends beyond end of SMB")); " end of SMB"));
} }
} else { } else {
cERROR(1, ("No session structure passed in.")); cERROR(1, ("No session structure passed in."));
@ -2903,13 +3011,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
cpu_to_le16(len); cpu_to_le16(len);
} }
/* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); /* SecurityBlob->WorkstationName.Length =
cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
SecurityBlob->WorkstationName.Length *= 2; SecurityBlob->WorkstationName.Length *= 2;
SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); SecurityBlob->WorkstationName.MaximumLength =
SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); cpu_to_le16(SecurityBlob->WorkstationName.Length);
SecurityBlob->WorkstationName.Buffer =
cpu_to_le32(SecurityBlobLength);
bcc_ptr += SecurityBlob->WorkstationName.Length; bcc_ptr += SecurityBlob->WorkstationName.Length;
SecurityBlobLength += SecurityBlob->WorkstationName.Length; SecurityBlobLength += SecurityBlob->WorkstationName.Length;
SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */ SecurityBlob->WorkstationName.Length =
cpu_to_le16(SecurityBlob->WorkstationName.Length); */
if ((long) bcc_ptr % 2) { if ((long) bcc_ptr % 2) {
*bcc_ptr = 0; *bcc_ptr = 0;
@ -2995,15 +3107,18 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 blob_len = __u16 blob_len =
le16_to_cpu(pSMBr->resp.SecurityBlobLength); le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN) if (action & GUEST_LOGIN)
cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ cFYI(1, (" Guest login")); /* BB Should we set anything
in SesInfo struct ? */
/* if (SecurityBlob2->MessageType != NtLm??) { /* if (SecurityBlob2->MessageType != NtLm??) {
cFYI("Unexpected message type on auth response is %d")); cFYI("Unexpected message type on auth response is %d"));
} */ } */
if (ses) { if (ses) {
cFYI(1, cFYI(1,
("Does UID on challenge %d match auth response UID %d ", ("Check challenge UID %d vs auth response UID %d",
ses->Suid, smb_buffer_response->Uid)); ses->Suid, smb_buffer_response->Uid));
ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */ /* UID left in wire format */
ses->Suid = smb_buffer_response->Uid;
bcc_ptr = pByteArea(smb_buffer_response); bcc_ptr = pByteArea(smb_buffer_response);
/* response can have either 3 or 4 word count - Samba sends 3 */ /* response can have either 3 or 4 word count - Samba sends 3 */
if ((pSMBr->resp.hdr.WordCount == 3) if ((pSMBr->resp.hdr.WordCount == 3)
@ -3124,8 +3239,10 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
kfree(ses->serverNOS); kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len+1,GFP_KERNEL); ses->serverNOS = kzalloc(len+1,
strncpy(ses->serverNOS, bcc_ptr, len); GFP_KERNEL);
strncpy(ses->serverNOS,
bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
@ -3133,19 +3250,24 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
if (ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = kzalloc(len+1,GFP_KERNEL); ses->serverDomain =
strncpy(ses->serverDomain, bcc_ptr, len); kzalloc(len+1,
GFP_KERNEL);
strncpy(ses->serverDomain,
bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
} else } else
cFYI(1, cFYI(1,
("Variable field of length %d extends beyond end of smb ", ("field of length %d "
"extends beyond end of smb ",
len)); len));
} }
} else { } else {
cERROR(1, cERROR(1,
(" Security Blob Length extends beyond end of SMB")); (" Security Blob extends beyond end "
"of SMB"));
} }
} else { } else {
cERROR(1, ("No session structure passed in.")); cERROR(1, ("No session structure passed in."));
@ -3285,7 +3407,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr[1] = 0; bcc_ptr[1] = 0;
bcc_ptr += 2; bcc_ptr += 2;
} }
/* else do not bother copying these informational fields */ /* else do not bother copying these information fields*/
} else { } else {
length = strnlen(bcc_ptr, 1024); length = strnlen(bcc_ptr, 1024);
if ((bcc_ptr + length) - if ((bcc_ptr + length) -
@ -3297,7 +3419,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
strncpy(tcon->nativeFileSystem, bcc_ptr, strncpy(tcon->nativeFileSystem, bcc_ptr,
length); length);
} }
/* else do not bother copying these informational fields */ /* else do not bother copying these information fields*/
} }
if ((smb_buffer_response->WordCount == 3) || if ((smb_buffer_response->WordCount == 3) ||
(smb_buffer_response->WordCount == 7)) (smb_buffer_response->WordCount == 7))
@ -3344,9 +3466,9 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
FreeXid(xid); FreeXid(xid);
return 0; return 0;
} else if (rc == -ESHUTDOWN) { } else if (rc == -ESHUTDOWN) {
cFYI(1,("Waking up socket by sending it signal")); cFYI(1, ("Waking up socket by sending signal"));
if (cifsd_task) { if (cifsd_task) {
send_sig(SIGKILL,cifsd_task,1); force_sig(SIGKILL, cifsd_task);
kthread_stop(cifsd_task); kthread_stop(cifsd_task);
} }
rc = 0; rc = 0;
@ -3403,7 +3525,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
if (linuxExtEnabled == 0) if (linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX); pSesInfo->capabilities &= (~CAP_UNIX);
/* pSesInfo->sequence_number = 0;*/ /* pSesInfo->sequence_number = 0;*/
cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", cFYI(1,
("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
pSesInfo->server->secMode, pSesInfo->server->secMode,
pSesInfo->server->capabilities, pSesInfo->server->capabilities,
pSesInfo->server->timeAdj)); pSesInfo->server->timeAdj));
@ -3434,7 +3557,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
} else } else
v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
if (v2_response) { if (v2_response) {
CalcNTLMv2_response(pSesInfo,v2_response); CalcNTLMv2_response(pSesInfo,
v2_response);
/* if (first_time) /* if (first_time)
cifs_calculate_ntlmv2_mac_key( cifs_calculate_ntlmv2_mac_key(
pSesInfo->server->mac_signing_key, pSesInfo->server->mac_signing_key,
@ -3453,7 +3577,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
if (first_time) if (first_time)
cifs_calculate_mac_key( cifs_calculate_mac_key(
pSesInfo->server->mac_signing_key, &pSesInfo->server->mac_signing_key,
ntlm_session_key, ntlm_session_key,
pSesInfo->password); pSesInfo->password);
} }
@ -3473,7 +3597,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
if (first_time) if (first_time)
cifs_calculate_mac_key( cifs_calculate_mac_key(
pSesInfo->server->mac_signing_key, &pSesInfo->server->mac_signing_key,
ntlm_session_key, pSesInfo->password); ntlm_session_key, pSesInfo->password);
rc = CIFSSessSetup(xid, pSesInfo, rc = CIFSSessSetup(xid, pSesInfo,

View file

@ -207,8 +207,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
} else { } else {
/* If Open reported that we actually created a file /* If Open reported that we actually created a file
then we now have to set the mode if possible */ then we now have to set the mode if possible */
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
(oplock & CIFS_CREATE_ACTION)) {
mode &= ~current->fs->umask; mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
@ -235,8 +234,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
/* Could set r/o dos attribute if mode & 0222 == 0 */ /* Could set r/o dos attribute if mode & 0222 == 0 */
} }
/* BB server might mask mode so we have to query for Unix case*/ /* server might mask mode so we have to query for it */
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb, xid); inode->i_sb, xid);
else { else {
@ -264,7 +263,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
direntry->d_op = &cifs_dentry_ops; direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
} }
if ((nd->flags & LOOKUP_OPEN) == FALSE) { if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
((nd->flags & LOOKUP_OPEN) == FALSE)) {
/* mknod case - do not leave file open */ /* mknod case - do not leave file open */
CIFSSMBClose(xid, pTcon, fileHandle); CIFSSMBClose(xid, pTcon, fileHandle);
} else if (newinode) { } else if (newinode) {
@ -336,7 +336,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if (full_path == NULL) if (full_path == NULL)
rc = -ENOMEM; rc = -ENOMEM;
else if (pTcon->ses->capabilities & CAP_UNIX) { else if (pTcon->unix_ext) {
mode &= ~current->fs->umask; mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@ -490,7 +490,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
cFYI(1, cFYI(1,
(" Full path: %s inode = 0x%p", full_path, direntry->d_inode)); (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newInode, full_path, rc = cifs_get_inode_info_unix(&newInode, full_path,
parent_dir_inode->i_sb, xid); parent_dir_inode->i_sb, xid);
else else

View file

@ -26,23 +26,36 @@
/* /*
* See Documentation/filesystems/Exporting * See Documentation/filesystems/Exporting
* and examples in fs/exportfs * and examples in fs/exportfs
*
* Since cifs is a network file system, an "fsid" must be included for
* any nfs exports file entries which refer to cifs paths. In addition
* the cifs mount must be mounted with the "serverino" option (ie use stable
* server inode numbers instead of locally generated temporary ones).
* Although cifs inodes do not use generation numbers (have generation number
* of zero) - the inode number alone should be good enough for simple cases
* in which users want to export cifs shares with NFS. The decode and encode
* could be improved by using a new routine which expects 64 bit inode numbers
* instead of the default 32 bit routines in fs/exportfs
*
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/exportfs.h> #include <linux/exportfs.h>
#include "cifsglob.h"
#include "cifs_debug.h"
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
static struct dentry *cifs_get_parent(struct dentry *dentry) static struct dentry *cifs_get_parent(struct dentry *dentry)
{ {
/* BB need to add code here eventually to enable export via NFSD */ /* BB need to add code here eventually to enable export via NFSD */
cFYI(1, ("get parent for %p", dentry));
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
} }
struct export_operations cifs_export_ops = { struct export_operations cifs_export_ops = {
.get_parent = cifs_get_parent, .get_parent = cifs_get_parent,
/* Following five export operations are unneeded so far and can default */ /* Following five export operations are unneeded so far and can default:
/* .get_dentry = .get_dentry =
.get_name = .get_name =
.find_exported_dentry = .find_exported_dentry =
.decode_fh = .decode_fh =

View file

@ -3,7 +3,7 @@
* *
* vfs operations that deal with files * vfs operations that deal with files
* *
* Copyright (C) International Business Machines Corp., 2002,2003 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org) * Jeremy Allison (jra@samba.org)
* *
@ -138,7 +138,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
} }
client_can_cache: client_can_cache:
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode, rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
full_path, inode->i_sb, xid); full_path, inode->i_sb, xid);
else else
@ -303,7 +303,7 @@ int cifs_open(struct inode *inode, struct file *file)
if (oplock & CIFS_CREATE_ACTION) { if (oplock & CIFS_CREATE_ACTION) {
/* time to set mode which we can not set earlier due to /* time to set mode which we can not set earlier due to
problems creating new read-only files */ problems creating new read-only files */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { if (pTcon->unix_ext) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, CIFSSMBUnixSetPerms(xid, pTcon, full_path,
inode->i_mode, inode->i_mode,
(__u64)-1, (__u64)-1, 0 /* dev */, (__u64)-1, (__u64)-1, 0 /* dev */,
@ -430,7 +430,7 @@ reopen_error_exit:
go to server to get inode info */ go to server to get inode info */
pCifsInode->clientCanCacheAll = FALSE; pCifsInode->clientCanCacheAll = FALSE;
pCifsInode->clientCanCacheRead = FALSE; pCifsInode->clientCanCacheRead = FALSE;
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode, rc = cifs_get_inode_info_unix(&inode,
full_path, inode->i_sb, xid); full_path, inode->i_sb, xid);
else else
@ -502,7 +502,8 @@ int cifs_close(struct inode *inode, struct file *file)
timeout *= 4; timeout *= 4;
} }
if (atomic_read(&pSMBFile->wrtPending)) if (atomic_read(&pSMBFile->wrtPending))
cERROR(1,("close with pending writes")); cERROR(1,
("close with pending writes"));
rc = CIFSSMBClose(xid, pTcon, rc = CIFSSMBClose(xid, pTcon,
pSMBFile->netfid); pSMBFile->netfid);
} }
@ -554,7 +555,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
if (pCFileStruct) { if (pCFileStruct) {
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); struct cifs_sb_info *cifs_sb =
CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
@ -594,7 +596,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
static int store_file_lock(struct cifsFileInfo *fid, __u64 len, static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
__u64 offset, __u8 lockType) __u64 offset, __u8 lockType)
{ {
struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); struct cifsLockInfo *li =
kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
if (li == NULL) if (li == NULL)
return -ENOMEM; return -ENOMEM;
li->offset = offset; li->offset = offset;
@ -741,10 +744,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
length, pfLock, length, pfLock,
posix_lock_type, wait_flag); posix_lock_type, wait_flag);
} else { } else {
struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data; struct cifsFileInfo *fid =
(struct cifsFileInfo *)file->private_data;
if (numLock) { if (numLock) {
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, rc = CIFSSMBLock(xid, pTcon, netfid, length,
pfLock->fl_start,
0, numLock, lockType, wait_flag); 0, numLock, lockType, wait_flag);
if (rc == 0) { if (rc == 0) {
@ -763,7 +768,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
list_for_each_entry_safe(li, tmp, &fid->llist, llist) { list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
if (pfLock->fl_start <= li->offset && if (pfLock->fl_start <= li->offset &&
length >= li->length) { length >= li->length) {
stored_rc = CIFSSMBLock(xid, pTcon, netfid, stored_rc = CIFSSMBLock(xid, pTcon,
netfid,
li->length, li->offset, li->length, li->offset,
1, 0, li->type, FALSE); 1, 0, li->type, FALSE);
if (stored_rc) if (stored_rc)
@ -1030,7 +1036,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
/* if it fails, try another handle - might be */ /* if it fails, try another handle - might be */
/* dangerous to hold up writepages with retry */ /* dangerous to hold up writepages with retry */
if (rc) { if (rc) {
cFYI(1,("failed on reopen file in wp")); cFYI(1,
("failed on reopen file in wp"));
read_lock(&GlobalSMBSeslock); read_lock(&GlobalSMBSeslock);
/* can not use this handle, no write /* can not use this handle, no write
pending on this one after all */ pending on this one after all */
@ -1279,7 +1286,7 @@ retry:
1); 1);
atomic_dec(&open_file->wrtPending); atomic_dec(&open_file->wrtPending);
if (rc || bytes_written < bytes_to_write) { if (rc || bytes_written < bytes_to_write) {
cERROR(1,("Write2 ret %d, written = %d", cERROR(1, ("Write2 ret %d, wrote %d",
rc, bytes_written)); rc, bytes_written));
/* BB what if continued retry is /* BB what if continued retry is
requested via mount flags? */ requested via mount flags? */
@ -1720,7 +1727,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
pagevec_init(&lru_pvec, 0); pagevec_init(&lru_pvec, 0);
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("rpages: num pages %d", num_pages));
#endif
for (i = 0; i < num_pages; ) { for (i = 0; i < num_pages; ) {
unsigned contig_pages; unsigned contig_pages;
struct page *tmp_page; struct page *tmp_page;
@ -1753,7 +1762,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
/* Read size needs to be in multiples of one page */ /* Read size needs to be in multiples of one page */
read_size = min_t(const unsigned int, read_size, read_size = min_t(const unsigned int, read_size,
cifs_sb->rsize & PAGE_CACHE_MASK); cifs_sb->rsize & PAGE_CACHE_MASK);
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("rpages: read size 0x%x contiguous pages %d",
read_size, contig_pages));
#endif
rc = -EAGAIN; rc = -EAGAIN;
while (rc == -EAGAIN) { while (rc == -EAGAIN) {
if ((open_file->invalidHandle) && if ((open_file->invalidHandle) &&
@ -1955,14 +1967,7 @@ static int cifs_prepare_write(struct file *file, struct page *page,
* We don't need to read data beyond the end of the file. * We don't need to read data beyond the end of the file.
* zero it, and set the page uptodate * zero it, and set the page uptodate
*/ */
void *kaddr = kmap_atomic(page, KM_USER0); simple_prepare_write(file, page, from, to);
if (from)
memset(kaddr, 0, from);
if (to < PAGE_CACHE_SIZE)
memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
SetPageUptodate(page); SetPageUptodate(page);
} else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
/* might as well read a page, it is fast enough */ /* might as well read a page, it is fast enough */

View file

@ -285,7 +285,6 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, pTcon, netfid);
} }
return rc; return rc;
} }
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
@ -317,8 +316,6 @@ static int get_sfu_uid_mode(struct inode * inode,
#else #else
return -EOPNOTSUPP; return -EOPNOTSUPP;
#endif #endif
} }
int cifs_get_inode_info(struct inode **pinode, int cifs_get_inode_info(struct inode **pinode,
@ -364,7 +361,6 @@ int cifs_get_inode_info(struct inode **pinode,
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
adjustTZ = TRUE; adjustTZ = TRUE;
} }
} }
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) { if (rc) {
@ -471,7 +467,8 @@ int cifs_get_inode_info(struct inode **pinode,
/* new inode, can safely set these fields */ /* new inode, can safely set these fields */
inode->i_mode = cifs_sb->mnt_file_mode; inode->i_mode = cifs_sb->mnt_file_mode;
else /* since we set the inode type below we need to mask off else /* since we set the inode type below we need to mask off
to avoid strange results if type changes and both get orred in */ to avoid strange results if type changes and both
get orred in */
inode->i_mode &= ~S_IFMT; inode->i_mode &= ~S_IFMT;
/* if (attr & ATTR_REPARSE) */ /* if (attr & ATTR_REPARSE) */
/* We no longer handle these as symlinks because we could not /* We no longer handle these as symlinks because we could not
@ -586,7 +583,8 @@ void cifs_read_inode(struct inode *inode)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
xid = GetXid(); xid = GetXid();
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
if (cifs_sb->tcon->unix_ext)
cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
else else
cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid);
@ -623,9 +621,21 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
if ((pTcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, ("posix del rc %d", rc));
if ((rc == 0) || (rc == -ENOENT))
goto psx_del_no_retry;
}
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
psx_del_no_retry:
if (!rc) { if (!rc) {
if (direntry->d_inode) if (direntry->d_inode)
drop_nlink(direntry->d_inode); drop_nlink(direntry->d_inode);
@ -849,8 +859,9 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_data.a_ops = &cifs_addr_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops;
if (isNewInode) if (isNewInode)
return; /* No sense invalidating pages for new inode since we return; /* No sense invalidating pages for new inode
have not started caching readahead file data yet */ since we we have not started caching
readahead file data yet */
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
(local_size == tmp_inode->i_size)) { (local_size == tmp_inode->i_size)) {
@ -920,7 +931,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
int obj_type; int obj_type;
if (pInfo->Type == -1) /* no return info - go query */ if (pInfo->Type == -1) /* no return info - go query */
goto mkdir_get_info; goto mkdir_get_info;
/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
to set uid/gid */
inc_nlink(inode); inc_nlink(inode);
if (pTcon->nocase) if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops; direntry->d_op = &cifs_ci_dentry_ops;
@ -970,7 +982,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
} else { } else {
mkdir_get_info: mkdir_get_info:
inc_nlink(inode); inc_nlink(inode);
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb, xid); inode->i_sb, xid);
else else
@ -986,7 +998,7 @@ mkdir_get_info:
* failed to get it from the server or was set bogus */ * failed to get it from the server or was set bogus */
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
direntry->d_inode->i_nlink = 2; direntry->d_inode->i_nlink = 2;
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { if (pTcon->unix_ext) {
mode &= ~current->fs->umask; mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@ -1119,7 +1131,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
if (info_buf_source != NULL) { if (info_buf_source != NULL) {
info_buf_target = info_buf_source + 1; info_buf_target = info_buf_source + 1;
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
info_buf_source, info_buf_source,
cifs_sb_source->local_nls, cifs_sb_source->local_nls,
@ -1247,7 +1259,7 @@ int cifs_revalidate(struct dentry *direntry)
local_mtime = direntry->d_inode->i_mtime; local_mtime = direntry->d_inode->i_mtime;
local_size = direntry->d_inode->i_size; local_size = direntry->d_inode->i_size;
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { if (cifs_sb->tcon->unix_ext) {
rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
direntry->d_sb, xid); direntry->d_sb, xid);
if (rc) { if (rc) {
@ -1335,17 +1347,13 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
pgoff_t index = from >> PAGE_CACHE_SHIFT; pgoff_t index = from >> PAGE_CACHE_SHIFT;
unsigned offset = from & (PAGE_CACHE_SIZE - 1); unsigned offset = from & (PAGE_CACHE_SIZE - 1);
struct page *page; struct page *page;
char *kaddr;
int rc = 0; int rc = 0;
page = grab_cache_page(mapping, index); page = grab_cache_page(mapping, index);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
kaddr = kmap_atomic(page, KM_USER0); zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
return rc; return rc;
@ -1535,7 +1543,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
mode = attrs->ia_mode; mode = attrs->ia_mode;
} }
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) if ((pTcon->unix_ext)
&& (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
0 /* dev_t */, cifs_sb->local_nls, 0 /* dev_t */, cifs_sb->local_nls,

View file

@ -3,7 +3,7 @@
* *
* vfs operations that deal with io control * vfs operations that deal with io control
* *
* Copyright (C) International Business Machines Corp., 2005 * Copyright (C) International Business Machines Corp., 2005,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify

View file

@ -55,7 +55,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
goto cifs_hl_exit; goto cifs_hl_exit;
} }
if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) /* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
if (pTcon->unix_ext)
rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
cifs_sb_target->local_nls, cifs_sb_target->local_nls,
cifs_sb_target->mnt_cifs_flags & cifs_sb_target->mnt_cifs_flags &
@ -129,13 +130,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
goto out; goto out;
} }
/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ /* We could change this to:
if (pTcon->unix_ext)
but there does not seem any point in refusing to
get symlink info if we can, even if unix extensions
turned off for this mount */
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
target_path, target_path,
PATH_MAX-1, PATH_MAX-1,
cifs_sb->local_nls); cifs_sb->local_nls);
else { else {
/* BB add read reparse point symlink code here */
/* rc = CIFSSMBQueryReparseLinkInfo */ /* rc = CIFSSMBQueryReparseLinkInfo */
/* BB Add code to Query ReparsePoint info */ /* BB Add code to Query ReparsePoint info */
/* BB Add MAC style xsymlink check here if enabled */ /* BB Add MAC style xsymlink check here if enabled */
@ -185,14 +192,15 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
cFYI(1, ("symname is %s", symname)); cFYI(1, ("symname is %s", symname));
/* BB what if DFS and this volume is on different share? BB */ /* BB what if DFS and this volume is on different share? BB */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
cifs_sb->local_nls); cifs_sb->local_nls);
/* else /* else
rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */ rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
cifs_sb_target->local_nls); */
if (rc == 0) { if (rc == 0) {
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb, xid); inode->i_sb, xid);
else else
@ -262,7 +270,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
return -ENOMEM; return -ENOMEM;
} }
/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ /* BB add read reparse point symlink code and
Unix extensions symlink code here BB */
/* We could disable this based on pTcon->unix_ext flag instead ... but why? */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
tmpbuffer, tmpbuffer,
@ -271,7 +281,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
cERROR(1, ("SFU style symlinks not implemented yet")); cERROR(1, ("SFU style symlinks not implemented yet"));
/* add open and read as in fs/cifs/inode.c */ /* add open and read as in fs/cifs/inode.c */
} else { } else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT, &fid, &oplock, NULL, OPEN_REPARSE_POINT, &fid, &oplock, NULL,
@ -285,7 +294,8 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
fid, fid,
cifs_sb->local_nls); cifs_sb->local_nls);
if (CIFSSMBClose(xid, pTcon, fid)) { if (CIFSSMBClose(xid, pTcon, fid)) {
cFYI(1,("Error closing junction point (open for ioctl)")); cFYI(1, ("Error closing junction point "
"(open for ioctl)"));
} }
if (rc == -EIO) { if (rc == -EIO) {
/* Query if DFS Junction */ /* Query if DFS Junction */
@ -293,28 +303,36 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
GFP_KERNEL); GFP_KERNEL);
if (tmp_path) { if (tmp_path) {
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); strncpy(tmp_path, pTcon->treeName,
strncat(tmp_path, full_path, MAX_PATHCONF); MAX_TREE_SIZE);
rc = get_dfs_path(xid, pTcon->ses, tmp_path, strncat(tmp_path, full_path,
MAX_PATHCONF);
rc = get_dfs_path(xid, pTcon->ses,
tmp_path,
cifs_sb->local_nls, cifs_sb->local_nls,
&num_referrals, &referrals, &num_referrals, &referrals,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); cFYI(1, ("Get DFS for %s rc = %d ",
tmp_path, rc));
if ((num_referrals == 0) && (rc == 0)) if ((num_referrals == 0) && (rc == 0))
rc = -EACCES; rc = -EACCES;
else { else {
cFYI(1,("num referral: %d",num_referrals)); cFYI(1, ("num referral: %d",
num_referrals));
if (referrals) { if (referrals) {
cFYI(1,("referral string: %s", referrals)); cFYI(1,("referral string: %s", referrals));
strncpy(tmpbuffer, referrals, len-1); strncpy(tmpbuffer,
referrals,
len-1);
} }
} }
kfree(referrals); kfree(referrals);
kfree(tmp_path); kfree(tmp_path);
} }
/* BB add code like else decode referrals then memcpy to /* BB add code like else decode referrals
tmpbuffer and free referrals string array BB */ then memcpy to tmpbuffer and free referrals
string array BB */
} }
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* fs/cifs/misc.c * fs/cifs/misc.c
* *
* Copyright (C) International Business Machines Corp., 2002,2005 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
@ -47,8 +47,10 @@ _GetXid(void)
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
GlobalTotalActiveXid++; GlobalTotalActiveXid++;
/* keep high water mark for number of simultaneous ops in filesystem */
if (GlobalTotalActiveXid > GlobalMaxActiveXid) if (GlobalTotalActiveXid > GlobalMaxActiveXid)
GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ GlobalMaxActiveXid = GlobalTotalActiveXid;
if (GlobalTotalActiveXid > 65000) if (GlobalTotalActiveXid > 65000)
cFYI(1, ("warning: more than 65000 requests active")); cFYI(1, ("warning: more than 65000 requests active"));
xid = GlobalCurrentXid++; xid = GlobalCurrentXid++;
@ -148,8 +150,8 @@ cifs_buf_get(void)
but it may be more efficient to always alloc same size but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */ defaults to this and can not be bigger */
ret_buf = ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp,
(struct smb_hdr *) mempool_alloc(cifs_req_poolp, GFP_KERNEL | GFP_NOFS); GFP_KERNEL | GFP_NOFS);
/* clear the first few header bytes */ /* clear the first few header bytes */
/* for most paths, more is cleared in header_assemble */ /* for most paths, more is cleared in header_assemble */
@ -187,8 +189,8 @@ cifs_small_buf_get(void)
but it may be more efficient to always alloc same size but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */ defaults to this and can not be bigger */
ret_buf = ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp,
(struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, GFP_KERNEL | GFP_NOFS); GFP_KERNEL | GFP_NOFS);
if (ret_buf) { if (ret_buf) {
/* No need to clear memory here, cleared in header assemble */ /* No need to clear memory here, cleared in header assemble */
/* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
@ -351,7 +353,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
/* with userid/password pairs found on the smb session */ /* with userid/password pairs found on the smb session */
/* for other target tcp/ip addresses BB */ /* for other target tcp/ip addresses BB */
if (current->fsuid != treeCon->ses->linux_uid) { if (current->fsuid != treeCon->ses->linux_uid) {
cFYI(1,("Multiuser mode and UID did not match tcon uid")); cFYI(1, ("Multiuser mode and UID "
"did not match tcon uid"));
read_lock(&GlobalSMBSeslock); read_lock(&GlobalSMBSeslock);
list_for_each(temp_item, &GlobalSMBSessionList) { list_for_each(temp_item, &GlobalSMBSessionList) {
ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
@ -362,7 +365,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
break; break;
} else { } else {
/* BB eventually call cifs_setup_session here */ /* BB eventually call cifs_setup_session here */
cFYI(1,("local UID found but smb sess with this server does not exist")); cFYI(1, ("local UID found but no smb sess with this server exists"));
} }
} }
} }
@ -399,7 +402,7 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
if (smb->Command == SMB_COM_LOCKING_ANDX) if (smb->Command == SMB_COM_LOCKING_ANDX)
return 0; return 0;
else else
cERROR(1, ("Rcvd Request not response")); cERROR(1, ("Received Request not response"));
} }
} else { /* bad signature or mid */ } else { /* bad signature or mid */
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
@ -459,7 +462,8 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
clc_len = smbCalcSize_LE(smb); clc_len = smbCalcSize_LE(smb);
if (4 + len != length) { if (4 + len != length) {
cERROR(1, ("Length read does not match RFC1001 length %d",len)); cERROR(1, ("Length read does not match RFC1001 length %d",
len));
return 1; return 1;
} }
@ -514,14 +518,16 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
pnotify = (struct file_notify_information *) pnotify = (struct file_notify_information *)
((char *)&pSMBr->hdr.Protocol + data_offset); ((char *)&pSMBr->hdr.Protocol + data_offset);
cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName, cFYI(1, ("dnotify on %s Action: 0x%x",
pnotify->FileName,
pnotify->Action)); /* BB removeme BB */ pnotify->Action)); /* BB removeme BB */
/* cifs_dump_mem("Rcvd notify Data: ",buf, /* cifs_dump_mem("Rcvd notify Data: ",buf,
sizeof(struct smb_hdr)+60); */ sizeof(struct smb_hdr)+60); */
return TRUE; return TRUE;
} }
if (pSMBr->hdr.Status.CifsError) { if (pSMBr->hdr.Status.CifsError) {
cFYI(1,("notify err 0x%d",pSMBr->hdr.Status.CifsError)); cFYI(1, ("notify err 0x%d",
pSMBr->hdr.Status.CifsError));
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -547,7 +553,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
if (pSMB->hdr.WordCount != 8) if (pSMB->hdr.WordCount != 8)
return FALSE; return FALSE;
cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); cFYI(1, ("oplock type 0x%d level 0x%d",
pSMB->LockType, pSMB->OplockLevel));
if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
return FALSE; return FALSE;
@ -563,7 +570,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
if (pSMB->Fid == netfile->netfid) { if (pSMB->Fid == netfile->netfid) {
struct cifsInodeInfo *pCifsInode; struct cifsInodeInfo *pCifsInode;
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
cFYI(1,("file id match, oplock break")); cFYI(1,
("file id match, oplock break"));
pCifsInode = pCifsInode =
CIFS_I(netfile->pInode); CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = FALSE; pCifsInode->clientCanCacheAll = FALSE;
@ -574,7 +582,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
AllocOplockQEntry(netfile->pInode, AllocOplockQEntry(netfile->pInode,
netfile->netfid, netfile->netfid,
tcon); tcon);
cFYI(1,("about to wake up oplock thd")); cFYI(1,
("about to wake up oplock thread"));
if (oplockThread) if (oplockThread)
wake_up_process(oplockThread); wake_up_process(oplockThread);
return TRUE; return TRUE;

View file

@ -7,7 +7,6 @@
* Error mapping routines from Samba libsmb/errormap.c * Error mapping routines from Samba libsmb/errormap.c
* Copyright (C) Andrew Tridgell 2001 * Copyright (C) Andrew Tridgell 2001
* *
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -30,9 +29,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <asm/div64.h> #include <asm/div64.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#ifdef CONFIG_CIFS_EXPERIMENTAL
#include <linux/inet.h> #include <linux/inet.h>
#endif
#include "cifsfs.h" #include "cifsfs.h"
#include "cifspdu.h" #include "cifspdu.h"
#include "cifsglob.h" #include "cifsglob.h"
@ -135,12 +132,11 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
int int
cifs_inet_pton(int address_family, char *cp, void *dst) cifs_inet_pton(int address_family, char *cp, void *dst)
{ {
#ifdef CONFIG_CIFS_EXPERIMENTAL
int ret = 0; int ret = 0;
/* calculate length by finding first slash or NULL */ /* calculate length by finding first slash or NULL */
/* BB Should we convert '/' slash to '\' here since it seems already done /* BB Should we convert '/' slash to '\' here since it seems already
before this */ * done before this */
if ( address_family == AF_INET ) { if ( address_family == AF_INET ) {
ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL); ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);
} else if ( address_family == AF_INET6 ) { } else if ( address_family == AF_INET6 ) {
@ -152,66 +148,6 @@ cifs_inet_pton(int address_family, char *cp,void *dst)
if (ret > 0) if (ret > 0)
ret = 1; ret = 1;
return ret; return ret;
#else
int value;
int digit;
int i;
char temp;
char bytes[4];
char *end = bytes;
static const int addr_class_max[4] =
{ 0xffffffff, 0xffffff, 0xffff, 0xff };
if(address_family != AF_INET)
return -EAFNOSUPPORT;
for (i = 0; i < 4; i++) {
bytes[i] = 0;
}
temp = *cp;
while (TRUE) {
if (!isdigit(temp))
return 0;
value = 0;
digit = 0;
for (;;) {
if (isascii(temp) && isdigit(temp)) {
value = (value * 10) + temp - '0';
temp = *++cp;
digit = 1;
} else
break;
}
if (temp == '.') {
if ((end > bytes + 2) || (value > 255))
return 0;
*end++ = value;
temp = *++cp;
} else if (temp == ':') {
cFYI(1,("IPv6 addresses not supported for CIFS mounts yet"));
return -1;
} else
break;
}
/* check for last characters */
if (temp != '\0' && (!isascii(temp) || !isspace(temp)))
if (temp != '\\') {
if (temp != '/')
return 0;
else
(*cp = '\\'); /* switch the slash the expected way */
}
if (value > addr_class_max[end - bytes])
return 0;
*((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
return 1; /* success */
#endif /* EXPERIMENTAL */
} }
/***************************************************************************** /*****************************************************************************
@ -393,8 +329,8 @@ static const struct {
ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, { ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, {
ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
/* { This NT error code was 'sqashed' /* { This NT error code was 'sqashed'
from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES from NT_STATUS_INSUFFICIENT_RESOURCES to
during the session setup } */ NT_STATUS_INSUFF_SERVER_RESOURCES during the session setup } */
{ {
ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, { ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, {
ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, { ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
@ -638,8 +574,8 @@ static const struct {
ERRDOS, 19, NT_STATUS_TOO_LATE}, { ERRDOS, 19, NT_STATUS_TOO_LATE}, {
ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET}, ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
/* { This NT error code was 'sqashed' /* { This NT error code was 'sqashed'
from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE from NT_STATUS_NO_TRUST_SAM_ACCOUNT to
during the session setup } */ NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE during the session setup } */
{ {
ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, { ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, {
ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, { ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, {
@ -832,7 +768,8 @@ map_smb_to_linux_error(struct smb_hdr *smb)
return 0; return 0;
if (smb->Flags2 & SMBFLG2_ERR_STATUS) { if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
/* translate the newer STATUS codes to old style errors and then to POSIX errors */ /* translate the newer STATUS codes to old style SMB errors
* and then to POSIX errors */
__u32 err = le32_to_cpu(smb->Status.CifsError); __u32 err = le32_to_cpu(smb->Status.CifsError);
if (cifsFYI & CIFS_RC) if (cifsFYI & CIFS_RC)
cifs_print_status(err); cifs_print_status(err);
@ -845,18 +782,19 @@ map_smb_to_linux_error(struct smb_hdr *smb)
/* old style errors */ /* old style errors */
/* DOS class smb error codes - map DOS */ /* DOS class smb error codes - map DOS */
if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */ if (smberrclass == ERRDOS) { /* 1 byte field no need to byte reverse */
for (i = 0; for (i = 0;
i < i <
sizeof (mapping_table_ERRDOS) / sizeof (mapping_table_ERRDOS) /
sizeof (struct smb_to_posix_error); i++) { sizeof (struct smb_to_posix_error); i++) {
if (mapping_table_ERRDOS[i].smb_err == 0) if (mapping_table_ERRDOS[i].smb_err == 0)
break; break;
else if (mapping_table_ERRDOS[i].smb_err == smberrcode) { else if (mapping_table_ERRDOS[i].smb_err ==
smberrcode) {
rc = mapping_table_ERRDOS[i].posix_code; rc = mapping_table_ERRDOS[i].posix_code;
break; break;
} }
/* else try the next error mapping one to see if it will match */ /* else try next error mapping one to see if match */
} }
} else if (smberrclass == ERRSRV) { /* server class of error codes */ } else if (smberrclass == ERRSRV) { /* server class of error codes */
for (i = 0; for (i = 0;
@ -865,18 +803,21 @@ map_smb_to_linux_error(struct smb_hdr *smb)
sizeof (struct smb_to_posix_error); i++) { sizeof (struct smb_to_posix_error); i++) {
if (mapping_table_ERRSRV[i].smb_err == 0) if (mapping_table_ERRSRV[i].smb_err == 0)
break; break;
else if (mapping_table_ERRSRV[i].smb_err == smberrcode) { else if (mapping_table_ERRSRV[i].smb_err ==
smberrcode) {
rc = mapping_table_ERRSRV[i].posix_code; rc = mapping_table_ERRSRV[i].posix_code;
break; break;
} }
/* else try the next error mapping one to see if it will match */ /* else try next error mapping to see if match */
} }
} }
/* else ERRHRD class errors or junk - return EIO */ /* else ERRHRD class errors or junk - return EIO */
cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc)); cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!",
smberrcode, rc));
/* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */ /* generic corrective action e.g. reconnect SMB session on
* ERRbaduid could be added */
return rc; return rc;
} }

View file

@ -1,7 +1,7 @@
/* /*
* fs/cifs/ntlmssp.h * fs/cifs/ntlmssp.h
* *
* Copyright (c) International Business Machines Corp., 2002,2006 * Copyright (c) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
@ -27,18 +27,18 @@
#define UnknownMessage cpu_to_le32(8) #define UnknownMessage cpu_to_le32(8)
/* Negotiate Flags */ /* Negotiate Flags */
#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode #define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are in unicode */
#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM #define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */
#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm #define NTLMSSP_REQUEST_TARGET 0x04 /* Server return its auth realm */
#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability #define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signature capability */
#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality #define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */
#define NTLMSSP_NEGOTIATE_DGRAM 0x0040 #define NTLMSSP_NEGOTIATE_DGRAM 0x0040
#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal #define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Sign/seal use LM session key */
#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication #define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server on same machine */
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign for all security levels */
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 #define NTLMSSP_TARGET_TYPE_SERVER 0x20000
#define NTLMSSP_TARGET_TYPE_SHARE 0x40000 #define NTLMSSP_TARGET_TYPE_SHARE 0x40000

View file

@ -51,7 +51,6 @@ static void dump_cifs_file_struct(struct file *file, char *label)
if (cf->srch_inf.emptyDir) { if (cf->srch_inf.emptyDir) {
cFYI(1, ("empty dir")); cFYI(1, ("empty dir"));
} }
} }
} }
#endif /* DEBUG2 */ #endif /* DEBUG2 */
@ -73,7 +72,8 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
qstring->hash = full_name_hash(qstring->name, qstring->len); qstring->hash = full_name_hash(qstring->name, qstring->len);
tmp_dentry = d_lookup(file->f_path.dentry, qstring); tmp_dentry = d_lookup(file->f_path.dentry, qstring);
if (tmp_dentry) { if (tmp_dentry) {
cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); cFYI(0, ("existing dentry with inode 0x%p",
tmp_dentry->d_inode));
*ptmp_inode = tmp_dentry->d_inode; *ptmp_inode = tmp_dentry->d_inode;
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
if (*ptmp_inode == NULL) { if (*ptmp_inode == NULL) {
@ -254,7 +254,6 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else else
tmp_inode->i_fop = &cifs_file_direct_ops; tmp_inode->i_fop = &cifs_file_direct_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops; tmp_inode->i_fop = &cifs_file_nobrl_ops;
else else
@ -400,8 +399,9 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_data.a_ops = &cifs_addr_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops;
if (isNewInode) if (isNewInode)
return; /* No sense invalidating pages for new inode since we return; /* No sense invalidating pages for new inode
have not started caching readahead file data yet */ since we have not started caching readahead
file data for it yet */
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
(local_size == tmp_inode->i_size)) { (local_size == tmp_inode->i_size)) {
@ -463,7 +463,9 @@ static int initiate_cifs_search(const int xid, struct file *file)
ffirst_retry: ffirst_retry:
/* test for Unix extensions */ /* test for Unix extensions */
if (pTcon->ses->capabilities & CAP_UNIX) { /* but now check for them on the share/mount not on the SMB session */
/* if (pTcon->ses->capabilities & CAP_UNIX) { */
if (pTcon->unix_ext) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
} else if ((pTcon->ses->capabilities & } else if ((pTcon->ses->capabilities &
(CAP_NT_SMBS | CAP_NT_FIND)) == 0) { (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
@ -524,8 +526,8 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
new_entry, end_of_smb, old_entry)); new_entry, end_of_smb, old_entry));
return NULL; return NULL;
} else if (((level == SMB_FIND_FILE_INFO_STANDARD) && } else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
(new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) || (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
((level != SMB_FIND_FILE_INFO_STANDARD) && || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
(new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) { (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
cERROR(1, ("search entry %p extends after end of SMB %p", cERROR(1, ("search entry %p extends after end of SMB %p",
new_entry, end_of_smb)); new_entry, end_of_smb));
@ -582,7 +584,8 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = pFindData->FileNameLength; len = pFindData->FileNameLength;
} else { } else {
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); cFYI(1, ("Unknown findfirst level %d",
cfile->srch_inf.info_level));
} }
if (filename) { if (filename) {
@ -680,7 +683,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
} }
rc = initiate_cifs_search(xid, file); rc = initiate_cifs_search(xid, file);
if (rc) { if (rc) {
cFYI(1,("error %d reinitiating a search on rewind",rc)); cFYI(1, ("error %d reinitiating a search on rewind",
rc));
return rc; return rc;
} }
} }
@ -727,7 +731,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
} }
if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
cFYI(1,("can not return entries pos_in_buf beyond last entry")); cFYI(1, ("can not return entries pos_in_buf beyond last"));
*num_to_ret = 0; *num_to_ret = 0;
} else } else
*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
@ -758,7 +762,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
len = strnlen(filename, PATH_MAX); len = strnlen(filename, PATH_MAX);
} }
/* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */ /* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
*pinum = pFindData->UniqueId; *pinum = pFindData->UniqueId;
} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
@ -863,7 +867,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
if (rc) { if (rc) {
/* inode created, we need to hash it with right inode number */ /* inode created, we need to hash it with right inode number */
if (inum != 0) { if (inum != 0) {
/* BB fixme - hash the 2 32 quantities bits together if necessary BB */ /* BB fixme - hash the 2 32 quantities bits together if
* necessary BB */
tmp_inode->i_ino = inum; tmp_inode->i_ino = inum;
} }
insert_inode_hash(tmp_inode); insert_inode_hash(tmp_inode);

View file

@ -3,7 +3,7 @@
* *
* SMB/CIFS session setup handling routines * SMB/CIFS session setup handling routines
* *
* Copyright (c) International Business Machines Corp., 2006 * Copyright (c) International Business Machines Corp., 2006, 2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
@ -51,7 +51,8 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
@ -170,7 +171,8 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
*pbcc_area = bcc_ptr; *pbcc_area = bcc_ptr;
} }
static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, static int decode_unicode_ssetup(char **pbcc_area, int bleft,
struct cifsSesInfo *ses,
const struct nls_table *nls_cp) const struct nls_table *nls_cp)
{ {
int rc = 0; int rc = 0;
@ -255,7 +257,8 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
return rc; return rc;
} }
static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, static int decode_ascii_ssetup(char **pbcc_area, int bleft,
struct cifsSesInfo *ses,
const struct nls_table *nls_cp) const struct nls_table *nls_cp)
{ {
int rc = 0; int rc = 0;
@ -347,7 +350,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
} else if ((type == NTLM) || (type == NTLMv2)) { } else if ((type == NTLM) || (type == NTLMv2)) {
/* For NTLMv2 failures eventually may need to retry NTLM */ /* For NTLMv2 failures eventually may need to retry NTLM */
wct = 13; /* old style NTLM sessionsetup */ wct = 13; /* old style NTLM sessionsetup */
} else /* same size for negotiate or auth, NTLMSSP or extended security */ } else /* same size: negotiate or auth, NTLMSSP or extended security */
wct = 12; wct = 12;
rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
@ -416,7 +419,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
if (first_time) /* should this be moved into common code if (first_time) /* should this be moved into common code
with similar ntlmv2 path? */ with similar ntlmv2 path? */
cifs_calculate_mac_key(ses->server->mac_signing_key, cifs_calculate_mac_key(&ses->server->mac_signing_key,
ntlm_session_key, ses->password); ntlm_session_key, ses->password);
/* copy session key */ /* copy session key */
@ -465,7 +468,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
bcc_ptr += LM2_SESS_KEY_SIZE; */ bcc_ptr += LM2_SESS_KEY_SIZE; */
memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); memcpy(bcc_ptr, (char *)v2_sess_key,
sizeof(struct ntlmv2_resp));
bcc_ptr += sizeof(struct ntlmv2_resp); bcc_ptr += sizeof(struct ntlmv2_resp);
kfree(v2_sess_key); kfree(v2_sess_key);
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
@ -531,7 +535,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
ses, nls_cp); ses, nls_cp);
else else
rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
ses, nls_cp);
ssetup_exit: ssetup_exit:
kfree(str_area); kfree(str_area);

View file

@ -97,7 +97,7 @@ _my_wcslen(__u16 * str)
static int static int
_my_mbstowcs(__u16 * dst, const unsigned char *src, int len) _my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
{ /* not a very good conversion routine - change/fix */ { /* BB not a very good conversion routine - change/fix */
int i; int i;
__u16 val; __u16 val;

View file

@ -1,7 +1,7 @@
/* /*
* fs/cifs/transport.c * fs/cifs/transport.c
* *
* Copyright (C) International Business Machines Corp., 2002,2005 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org) 2006. * Jeremy Allison (jra@samba.org) 2006.
* *
@ -333,8 +333,8 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
return -ENOENT; return -ENOENT;
} }
/* can not count locking commands against total since /* can not count locking commands against total
they are allowed to block on server */ as they are allowed to block on server */
/* update # of requests on the wire to server */ /* update # of requests on the wire to server */
if (long_op < 3) if (long_op < 3)
@ -559,7 +559,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
(ses->server->secMode & (SECMODE_SIGN_REQUIRED | (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) { SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(midQ->resp_buf, rc = cifs_verify_signature(midQ->resp_buf,
ses->server->mac_signing_key, &ses->server->mac_signing_key,
midQ->sequence_number+1); midQ->sequence_number+1);
if (rc) { if (rc) {
cERROR(1, ("Unexpected SMB signature")); cERROR(1, ("Unexpected SMB signature"));
@ -738,7 +738,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
(ses->server->secMode & (SECMODE_SIGN_REQUIRED | (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) { SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(out_buf, rc = cifs_verify_signature(out_buf,
ses->server->mac_signing_key, &ses->server->mac_signing_key,
midQ->sequence_number+1); midQ->sequence_number+1);
if (rc) { if (rc) {
cERROR(1, ("Unexpected SMB signature")); cERROR(1, ("Unexpected SMB signature"));
@ -982,7 +982,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
(ses->server->secMode & (SECMODE_SIGN_REQUIRED | (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) { SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(out_buf, rc = cifs_verify_signature(out_buf,
ses->server->mac_signing_key, &ses->server->mac_signing_key,
midQ->sequence_number+1); midQ->sequence_number+1);
if (rc) { if (rc) {
cERROR(1, ("Unexpected SMB signature")); cERROR(1, ("Unexpected SMB signature"));

View file

@ -1,7 +1,7 @@
/* /*
* fs/cifs/xattr.c * fs/cifs/xattr.c
* *
* Copyright (c) International Business Machines Corp., 2003 * Copyright (c) International Business Machines Corp., 2003, 2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
@ -71,7 +71,9 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name)
cFYI(1, ("Null xattr names not supported")); cFYI(1, ("Null xattr names not supported"));
} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
&& (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) { && (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name)); cFYI(1,
("illegal xattr request %s (only user namespace supported)",
ea_name));
/* BB what if no namespace prefix? */ /* BB what if no namespace prefix? */
/* Should we just pass them to server, except for /* Should we just pass them to server, except for
system and perhaps security prefixes? */ system and perhaps security prefixes? */
@ -168,7 +170,8 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
#else #else
cFYI(1, ("set POSIX ACL not supported")); cFYI(1, ("set POSIX ACL not supported"));
#endif #endif
} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
if (sb->s_flags & MS_POSIXACL) if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
@ -181,7 +184,8 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
cFYI(1, ("set default POSIX ACL not supported")); cFYI(1, ("set default POSIX ACL not supported"));
#endif #endif
} else { } else {
cFYI(1,("illegal xattr request %s (only user namespace supported)",ea_name)); cFYI(1, ("illegal xattr request %s (only user namespace"
" supported)", ea_name));
/* BB what if no namespace prefix? */ /* BB what if no namespace prefix? */
/* Should we just pass them to server, except for /* Should we just pass them to server, except for
system and perhaps security prefixes? */ system and perhaps security prefixes? */
@ -272,7 +276,6 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
CIFSSMBClose(xid, pTcon, fid); CIFSSMBClose(xid, pTcon, fid);
} }
} */ /* BB enable after fixing up return data */ } */ /* BB enable after fixing up return data */
#else #else
cFYI(1, ("query POSIX ACL not supported yet")); cFYI(1, ("query POSIX ACL not supported yet"));
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
@ -295,7 +298,9 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) { CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
cFYI(1, ("Security xattr namespace not supported yet")); cFYI(1, ("Security xattr namespace not supported yet"));
} else { } else {
cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name)); cFYI(1,
("illegal xattr request %s (only user namespace supported)",
ea_name));
} }
/* We could add an additional check for streams ie /* We could add an additional check for streams ie