mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-19 16:14:13 +08:00
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: cifs: use CreationTime like an i_generation field cifs: switch cifs_open and cifs_create to use CIFSSMBUnixSetFileInfo cifs: show "acl" in DebugData Features when it's compiled in cifs: move "ntlmssp" and "local_leases" options out of experimental code cifs: replace some hardcoded values with preprocessor constants cifs: remove unnecessary locking around sequence_number [CIFS] Fix minor merge conflict in fs/cifs/dir.c CIFS: Simplify cifs_open code CIFS: Simplify non-posix open stuff (try #2) CIFS: Add match_port check during looking for an existing connection (try #4) CIFS: Simplify ipv*_connect functions into one (try #4) cifs: Support NTLM2 session security during NTLMSSP authentication [try #5] cifs: don't overwrite dentry name in d_revalidate
This commit is contained in:
commit
f3ea597251
@ -64,7 +64,9 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
|
||||
void *buffer, uint16_t maxbuf)
|
||||
{
|
||||
const struct TCP_Server_Info *server = cookie_netfs_data;
|
||||
const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr;
|
||||
const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr;
|
||||
const struct sockaddr_in *addr = (struct sockaddr_in *) sa;
|
||||
const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa;
|
||||
struct cifs_server_key *key = buffer;
|
||||
uint16_t key_len = sizeof(struct cifs_server_key);
|
||||
|
||||
@ -76,16 +78,16 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
|
||||
*/
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
key->family = server->addr.sockAddr.sin_family;
|
||||
key->port = server->addr.sockAddr.sin_port;
|
||||
key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr;
|
||||
key->family = sa->sa_family;
|
||||
key->port = addr->sin_port;
|
||||
key->addr[0].ipv4_addr = addr->sin_addr;
|
||||
key_len += sizeof(key->addr[0].ipv4_addr);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
key->family = server->addr.sockAddr6.sin6_family;
|
||||
key->port = server->addr.sockAddr6.sin6_port;
|
||||
key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr;
|
||||
key->family = sa->sa_family;
|
||||
key->port = addr6->sin6_port;
|
||||
key->addr[0].ipv6_addr = addr6->sin6_addr;
|
||||
key_len += sizeof(key->addr[0].ipv6_addr);
|
||||
break;
|
||||
|
||||
|
@ -122,26 +122,24 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, "Features:");
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
seq_printf(m, " dfs");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_FSCACHE
|
||||
seq_printf(m, " fscache");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
seq_printf(m, " lanman");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_POSIX
|
||||
seq_printf(m, " posix");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
seq_printf(m, " spnego");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
seq_printf(m, " xattr");
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
seq_printf(m, " acl");
|
||||
#endif
|
||||
seq_putc(m, '\n');
|
||||
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
|
||||
|
@ -98,6 +98,8 @@ struct key *
|
||||
cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||
{
|
||||
struct TCP_Server_Info *server = sesInfo->server;
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
|
||||
char *description, *dp;
|
||||
size_t desc_len;
|
||||
struct key *spnego_key;
|
||||
@ -127,10 +129,10 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||
dp = description + strlen(description);
|
||||
|
||||
/* add the server address */
|
||||
if (server->addr.sockAddr.sin_family == AF_INET)
|
||||
sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr);
|
||||
else if (server->addr.sockAddr.sin_family == AF_INET6)
|
||||
sprintf(dp, "ip6=%pI6", &server->addr.sockAddr6.sin6_addr);
|
||||
if (server->dstaddr.ss_family == AF_INET)
|
||||
sprintf(dp, "ip4=%pI4", &sa->sin_addr);
|
||||
else if (server->dstaddr.ss_family == AF_INET6)
|
||||
sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
|
||||
else
|
||||
goto out;
|
||||
|
||||
|
@ -72,6 +72,7 @@ static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* must be called with server->srv_mutex held */
|
||||
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
|
||||
__u32 *pexpected_response_sequence_number)
|
||||
{
|
||||
@ -84,14 +85,12 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
|
||||
if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
|
||||
return rc;
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
cifs_pdu->Signature.Sequence.SequenceNumber =
|
||||
cpu_to_le32(server->sequence_number);
|
||||
cifs_pdu->Signature.Sequence.Reserved = 0;
|
||||
|
||||
*pexpected_response_sequence_number = server->sequence_number++;
|
||||
server->sequence_number++;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
|
||||
rc = cifs_calculate_signature(cifs_pdu, server, smb_signature);
|
||||
if (rc)
|
||||
@ -149,6 +148,7 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* must be called with server->srv_mutex held */
|
||||
int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
|
||||
__u32 *pexpected_response_sequence_number)
|
||||
{
|
||||
@ -162,14 +162,12 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
|
||||
if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
|
||||
return rc;
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
cifs_pdu->Signature.Sequence.SequenceNumber =
|
||||
cpu_to_le32(server->sequence_number);
|
||||
cifs_pdu->Signature.Sequence.Reserved = 0;
|
||||
|
||||
*pexpected_response_sequence_number = server->sequence_number++;
|
||||
server->sequence_number++;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
|
||||
rc = cifs_calc_signature2(iov, n_vec, server, smb_signature);
|
||||
if (rc)
|
||||
|
@ -329,6 +329,8 @@ cifs_alloc_inode(struct super_block *sb)
|
||||
cifs_inode->invalid_mapping = false;
|
||||
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
|
||||
cifs_inode->server_eof = 0;
|
||||
cifs_inode->uniqueid = 0;
|
||||
cifs_inode->createtime = 0;
|
||||
|
||||
/* Can not set i_flags here - they get immediately overwritten
|
||||
to zero by the VFS */
|
||||
@ -361,18 +363,19 @@ cifs_evict_inode(struct inode *inode)
|
||||
static void
|
||||
cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
|
||||
{
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
|
||||
|
||||
seq_printf(s, ",addr=");
|
||||
|
||||
switch (server->addr.sockAddr.sin_family) {
|
||||
switch (server->dstaddr.ss_family) {
|
||||
case AF_INET:
|
||||
seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr);
|
||||
seq_printf(s, "%pI4", &sa->sin_addr.s_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
seq_printf(s, "%pI6",
|
||||
&server->addr.sockAddr6.sin6_addr.s6_addr);
|
||||
if (server->addr.sockAddr6.sin6_scope_id)
|
||||
seq_printf(s, "%%%u",
|
||||
server->addr.sockAddr6.sin6_scope_id);
|
||||
seq_printf(s, "%pI6", &sa6->sin6_addr.s6_addr);
|
||||
if (sa6->sin6_scope_id)
|
||||
seq_printf(s, "%%%u", sa6->sin6_scope_id);
|
||||
break;
|
||||
default:
|
||||
seq_printf(s, "(unknown)");
|
||||
|
@ -163,10 +163,7 @@ struct TCP_Server_Info {
|
||||
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
||||
char *hostname; /* hostname portion of UNC string */
|
||||
struct socket *ssocket;
|
||||
union {
|
||||
struct sockaddr_in sockAddr;
|
||||
struct sockaddr_in6 sockAddr6;
|
||||
} addr;
|
||||
struct sockaddr_storage dstaddr;
|
||||
struct sockaddr_storage srcaddr; /* locally bind to this IP */
|
||||
wait_queue_head_t response_q;
|
||||
wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
|
||||
@ -210,7 +207,7 @@ struct TCP_Server_Info {
|
||||
char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
|
||||
/* 16th byte of RFC1001 workstation name is always null */
|
||||
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
||||
__u32 sequence_number; /* needed for CIFS PDU signature */
|
||||
__u32 sequence_number; /* for signing, protected by srv_mutex */
|
||||
struct session_key session_key;
|
||||
unsigned long lstrp; /* when we got last response from this server */
|
||||
u16 dialect; /* dialect index that server chose */
|
||||
@ -456,6 +453,7 @@ struct cifsInodeInfo {
|
||||
bool invalid_mapping:1; /* pagecache is invalid */
|
||||
u64 server_eof; /* current file size on server */
|
||||
u64 uniqueid; /* server inode number */
|
||||
u64 createtime; /* creation time on server */
|
||||
#ifdef CONFIG_CIFS_FSCACHE
|
||||
struct fscache_cookie *fscache;
|
||||
#endif
|
||||
@ -576,6 +574,7 @@ struct cifs_fattr {
|
||||
u64 cf_uniqueid;
|
||||
u64 cf_eof;
|
||||
u64 cf_bytes;
|
||||
u64 cf_createtime;
|
||||
uid_t cf_uid;
|
||||
gid_t cf_gid;
|
||||
umode_t cf_mode;
|
||||
|
@ -401,15 +401,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
||||
else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
|
||||
cFYI(1, "Kerberos only mechanism, enable extended security");
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
}
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
|
||||
} else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
|
||||
cFYI(1, "NTLMSSP only mechanism, enable extended security");
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < CIFS_NUM_PROT; i++) {
|
||||
|
@ -64,8 +64,8 @@ struct smb_vol {
|
||||
char *UNC;
|
||||
char *UNCip;
|
||||
char *iocharset; /* local code page for mapping to and from Unicode */
|
||||
char source_rfc1001_name[16]; /* netbios name of client */
|
||||
char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
|
||||
char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
|
||||
char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
|
||||
uid_t cred_uid;
|
||||
uid_t linux_uid;
|
||||
gid_t linux_gid;
|
||||
@ -115,8 +115,8 @@ struct smb_vol {
|
||||
#define TLINK_ERROR_EXPIRE (1 * HZ)
|
||||
#define TLINK_IDLE_EXPIRE (600 * HZ)
|
||||
|
||||
static int ipv4_connect(struct TCP_Server_Info *server);
|
||||
static int ipv6_connect(struct TCP_Server_Info *server);
|
||||
static int ip_connect(struct TCP_Server_Info *server);
|
||||
static int generic_ip_connect(struct TCP_Server_Info *server);
|
||||
static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
|
||||
static void cifs_prune_tlinks(struct work_struct *work);
|
||||
|
||||
@ -200,10 +200,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||
while ((server->tcpStatus != CifsExiting) &&
|
||||
(server->tcpStatus != CifsGood)) {
|
||||
try_to_freeze();
|
||||
if (server->addr.sockAddr6.sin6_family == AF_INET6)
|
||||
rc = ipv6_connect(server);
|
||||
else
|
||||
rc = ipv4_connect(server);
|
||||
|
||||
/* we should try only the port we connected to before */
|
||||
rc = generic_ip_connect(server);
|
||||
if (rc) {
|
||||
cFYI(1, "reconnect error %d", rc);
|
||||
msleep(3000);
|
||||
@ -477,7 +476,7 @@ incomplete_rcv:
|
||||
* initialize frame)
|
||||
*/
|
||||
cifs_set_port((struct sockaddr *)
|
||||
&server->addr.sockAddr, CIFS_PORT);
|
||||
&server->dstaddr, CIFS_PORT);
|
||||
cifs_reconnect(server);
|
||||
csocket = server->ssocket;
|
||||
wake_up(&server->response_q);
|
||||
@ -817,11 +816,11 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||
* informational, only used for servers that do not support
|
||||
* port 445 and it can be overridden at mount time
|
||||
*/
|
||||
memset(vol->source_rfc1001_name, 0x20, 15);
|
||||
for (i = 0; i < strnlen(nodename, 15); i++)
|
||||
memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
|
||||
for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
|
||||
vol->source_rfc1001_name[i] = toupper(nodename[i]);
|
||||
|
||||
vol->source_rfc1001_name[15] = 0;
|
||||
vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
|
||||
/* null target name indicates to use *SMBSERVR default called name
|
||||
if we end up sending RFC1001 session initialize */
|
||||
vol->target_rfc1001_name[0] = 0;
|
||||
@ -985,13 +984,11 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||
return 1;
|
||||
} else if (strnicmp(value, "krb5", 4) == 0) {
|
||||
vol->secFlg |= CIFSSEC_MAY_KRB5;
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
} else if (strnicmp(value, "ntlmsspi", 8) == 0) {
|
||||
vol->secFlg |= CIFSSEC_MAY_NTLMSSP |
|
||||
CIFSSEC_MUST_SIGN;
|
||||
} else if (strnicmp(value, "ntlmssp", 7) == 0) {
|
||||
vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
|
||||
#endif
|
||||
} else if (strnicmp(value, "ntlmv2i", 7) == 0) {
|
||||
vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
|
||||
CIFSSEC_MUST_SIGN;
|
||||
@ -1168,22 +1165,22 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||
if (!value || !*value || (*value == ' ')) {
|
||||
cFYI(1, "invalid (empty) netbiosname");
|
||||
} else {
|
||||
memset(vol->source_rfc1001_name, 0x20, 15);
|
||||
for (i = 0; i < 15; i++) {
|
||||
/* BB are there cases in which a comma can be
|
||||
valid in this workstation netbios name (and need
|
||||
special handling)? */
|
||||
|
||||
/* We do not uppercase netbiosname for user */
|
||||
memset(vol->source_rfc1001_name, 0x20,
|
||||
RFC1001_NAME_LEN);
|
||||
/*
|
||||
* FIXME: are there cases in which a comma can
|
||||
* be valid in workstation netbios name (and
|
||||
* need special handling)?
|
||||
*/
|
||||
for (i = 0; i < RFC1001_NAME_LEN; i++) {
|
||||
/* don't ucase netbiosname for user */
|
||||
if (value[i] == 0)
|
||||
break;
|
||||
else
|
||||
vol->source_rfc1001_name[i] =
|
||||
value[i];
|
||||
vol->source_rfc1001_name[i] = value[i];
|
||||
}
|
||||
/* The string has 16th byte zero still from
|
||||
set at top of the function */
|
||||
if ((i == 15) && (value[i] != 0))
|
||||
if (i == RFC1001_NAME_LEN && value[i] != 0)
|
||||
printk(KERN_WARNING "CIFS: netbiosname"
|
||||
" longer than 15 truncated.\n");
|
||||
}
|
||||
@ -1193,7 +1190,8 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||
cFYI(1, "empty server netbiosname specified");
|
||||
} else {
|
||||
/* last byte, type, is 0x20 for servr type */
|
||||
memset(vol->target_rfc1001_name, 0x20, 16);
|
||||
memset(vol->target_rfc1001_name, 0x20,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
|
||||
for (i = 0; i < 15; i++) {
|
||||
/* BB are there cases in which a comma can be
|
||||
@ -1210,7 +1208,7 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||
}
|
||||
/* The string has 16th byte zero still from
|
||||
set at top of the function */
|
||||
if ((i == 15) && (value[i] != 0))
|
||||
if (i == RFC1001_NAME_LEN && value[i] != 0)
|
||||
printk(KERN_WARNING "CIFS: server net"
|
||||
"biosname longer than 15 truncated.\n");
|
||||
}
|
||||
@ -1341,10 +1339,8 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||
vol->no_psx_acl = 0;
|
||||
} else if (strnicmp(data, "noacl", 5) == 0) {
|
||||
vol->no_psx_acl = 1;
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
} else if (strnicmp(data, "locallease", 6) == 0) {
|
||||
vol->local_lease = 1;
|
||||
#endif
|
||||
} else if (strnicmp(data, "sign", 4) == 0) {
|
||||
vol->secFlg |= CIFSSEC_MUST_SIGN;
|
||||
} else if (strnicmp(data, "seal", 4) == 0) {
|
||||
@ -1454,35 +1450,71 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no port is specified in addr structure, we try to match with 445 port
|
||||
* and if it fails - with 139 ports. It should be called only if address
|
||||
* families of server and addr are equal.
|
||||
*/
|
||||
static bool
|
||||
match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
|
||||
{
|
||||
unsigned short int port, *sport;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
|
||||
port = ((struct sockaddr_in *) addr)->sin_port;
|
||||
break;
|
||||
case AF_INET6:
|
||||
sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port;
|
||||
port = ((struct sockaddr_in6 *) addr)->sin6_port;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
port = htons(CIFS_PORT);
|
||||
if (port == *sport)
|
||||
return true;
|
||||
|
||||
port = htons(RFC1001_PORT);
|
||||
}
|
||||
|
||||
return port == *sport;
|
||||
}
|
||||
|
||||
static bool
|
||||
match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
|
||||
struct sockaddr *srcaddr)
|
||||
{
|
||||
struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
if (addr4->sin_addr.s_addr !=
|
||||
server->addr.sockAddr.sin_addr.s_addr)
|
||||
return false;
|
||||
if (addr4->sin_port &&
|
||||
addr4->sin_port != server->addr.sockAddr.sin_port)
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
|
||||
struct sockaddr_in *srv_addr4 =
|
||||
(struct sockaddr_in *)&server->dstaddr;
|
||||
|
||||
if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr)
|
||||
return false;
|
||||
break;
|
||||
case AF_INET6:
|
||||
}
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
|
||||
struct sockaddr_in6 *srv_addr6 =
|
||||
(struct sockaddr_in6 *)&server->dstaddr;
|
||||
|
||||
if (!ipv6_addr_equal(&addr6->sin6_addr,
|
||||
&server->addr.sockAddr6.sin6_addr))
|
||||
&srv_addr6->sin6_addr))
|
||||
return false;
|
||||
if (addr6->sin6_scope_id !=
|
||||
server->addr.sockAddr6.sin6_scope_id)
|
||||
return false;
|
||||
if (addr6->sin6_port &&
|
||||
addr6->sin6_port != server->addr.sockAddr6.sin6_port)
|
||||
if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return false; /* don't expect to be here */
|
||||
}
|
||||
|
||||
if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr))
|
||||
return false;
|
||||
@ -1549,6 +1581,9 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
|
||||
(struct sockaddr *)&vol->srcaddr))
|
||||
continue;
|
||||
|
||||
if (!match_port(server, addr))
|
||||
continue;
|
||||
|
||||
if (!match_security(server, vol))
|
||||
continue;
|
||||
|
||||
@ -1681,14 +1716,13 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
|
||||
cFYI(1, "attempting ipv6 connect");
|
||||
/* BB should we allow ipv6 on port 139? */
|
||||
/* other OS never observed in Wild doing 139 with v6 */
|
||||
memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
|
||||
memcpy(&tcp_ses->dstaddr, sin_server6,
|
||||
sizeof(struct sockaddr_in6));
|
||||
rc = ipv6_connect(tcp_ses);
|
||||
} else {
|
||||
memcpy(&tcp_ses->addr.sockAddr, sin_server,
|
||||
} else
|
||||
memcpy(&tcp_ses->dstaddr, sin_server,
|
||||
sizeof(struct sockaddr_in));
|
||||
rc = ipv4_connect(tcp_ses);
|
||||
}
|
||||
|
||||
rc = ip_connect(tcp_ses);
|
||||
if (rc < 0) {
|
||||
cERROR(1, "Error connecting to socket. Aborting operation");
|
||||
goto out_err_crypto_release;
|
||||
@ -1793,6 +1827,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
|
||||
{
|
||||
int rc = -ENOMEM, xid;
|
||||
struct cifsSesInfo *ses;
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
@ -1836,12 +1872,10 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
|
||||
|
||||
/* new SMB session uses our server ref */
|
||||
ses->server = server;
|
||||
if (server->addr.sockAddr6.sin6_family == AF_INET6)
|
||||
sprintf(ses->serverName, "%pI6",
|
||||
&server->addr.sockAddr6.sin6_addr);
|
||||
if (server->dstaddr.ss_family == AF_INET6)
|
||||
sprintf(ses->serverName, "%pI6", &addr6->sin6_addr);
|
||||
else
|
||||
sprintf(ses->serverName, "%pI4",
|
||||
&server->addr.sockAddr.sin_addr.s_addr);
|
||||
sprintf(ses->serverName, "%pI4", &addr->sin_addr);
|
||||
|
||||
if (volume_info->username)
|
||||
strncpy(ses->userName, volume_info->username,
|
||||
@ -2136,19 +2170,106 @@ bind_socket(struct TCP_Server_Info *server)
|
||||
}
|
||||
|
||||
static int
|
||||
ipv4_connect(struct TCP_Server_Info *server)
|
||||
ip_rfc1001_connect(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc = 0;
|
||||
int val;
|
||||
bool connected = false;
|
||||
__be16 orig_port = 0;
|
||||
/*
|
||||
* some servers require RFC1001 sessinit before sending
|
||||
* negprot - BB check reconnection in case where second
|
||||
* sessinit is sent but no second negprot
|
||||
*/
|
||||
struct rfc1002_session_packet *ses_init_buf;
|
||||
struct smb_hdr *smb_buf;
|
||||
ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
|
||||
GFP_KERNEL);
|
||||
if (ses_init_buf) {
|
||||
ses_init_buf->trailer.session_req.called_len = 32;
|
||||
|
||||
if (server->server_RFC1001_name &&
|
||||
server->server_RFC1001_name[0] != 0)
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.called_name,
|
||||
server->server_RFC1001_name,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
else
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.called_name,
|
||||
DEFAULT_CIFS_CALLED_NAME,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
|
||||
ses_init_buf->trailer.session_req.calling_len = 32;
|
||||
|
||||
/*
|
||||
* calling name ends in null (byte 16) from old smb
|
||||
* convention.
|
||||
*/
|
||||
if (server->workstation_RFC1001_name &&
|
||||
server->workstation_RFC1001_name[0] != 0)
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.calling_name,
|
||||
server->workstation_RFC1001_name,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
else
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.calling_name,
|
||||
"LINUX_CIFS_CLNT",
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
|
||||
ses_init_buf->trailer.session_req.scope1 = 0;
|
||||
ses_init_buf->trailer.session_req.scope2 = 0;
|
||||
smb_buf = (struct smb_hdr *)ses_init_buf;
|
||||
|
||||
/* sizeof RFC1002_SESSION_REQUEST with no scope */
|
||||
smb_buf->smb_buf_length = 0x81000044;
|
||||
rc = smb_send(server, smb_buf, 0x44);
|
||||
kfree(ses_init_buf);
|
||||
/*
|
||||
* RFC1001 layer in at least one server
|
||||
* requires very short break before negprot
|
||||
* presumably because not expecting negprot
|
||||
* to follow so fast. This is a simple
|
||||
* solution that works without
|
||||
* complicating the code and causes no
|
||||
* significant slowing down on mount
|
||||
* for everyone else
|
||||
*/
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
/*
|
||||
* else the negprot may still work without this
|
||||
* even though malloc failed
|
||||
*/
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
generic_ip_connect(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned short int sport;
|
||||
int slen, sfamily;
|
||||
struct socket *socket = server->ssocket;
|
||||
struct sockaddr *saddr;
|
||||
|
||||
saddr = (struct sockaddr *) &server->dstaddr;
|
||||
|
||||
if (server->dstaddr.ss_family == AF_INET6) {
|
||||
sport = ((struct sockaddr_in6 *) saddr)->sin6_port;
|
||||
slen = sizeof(struct sockaddr_in6);
|
||||
sfamily = AF_INET6;
|
||||
} else {
|
||||
sport = ((struct sockaddr_in *) saddr)->sin_port;
|
||||
slen = sizeof(struct sockaddr_in);
|
||||
sfamily = AF_INET;
|
||||
}
|
||||
|
||||
if (socket == NULL) {
|
||||
rc = sock_create_kern(PF_INET, SOCK_STREAM,
|
||||
rc = sock_create_kern(sfamily, SOCK_STREAM,
|
||||
IPPROTO_TCP, &socket);
|
||||
if (rc < 0) {
|
||||
cERROR(1, "Error %d creating socket", rc);
|
||||
server->ssocket = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2156,6 +2277,9 @@ ipv4_connect(struct TCP_Server_Info *server)
|
||||
cFYI(1, "Socket created");
|
||||
server->ssocket = socket;
|
||||
socket->sk->sk_allocation = GFP_NOFS;
|
||||
if (sfamily == AF_INET6)
|
||||
cifs_reclassify_socket6(socket);
|
||||
else
|
||||
cifs_reclassify_socket4(socket);
|
||||
}
|
||||
|
||||
@ -2163,52 +2287,14 @@ ipv4_connect(struct TCP_Server_Info *server)
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* user overrode default port */
|
||||
if (server->addr.sockAddr.sin_port) {
|
||||
rc = socket->ops->connect(socket, (struct sockaddr *)
|
||||
&server->addr.sockAddr,
|
||||
sizeof(struct sockaddr_in), 0);
|
||||
if (rc >= 0)
|
||||
connected = true;
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
/* save original port so we can retry user specified port
|
||||
later if fall back ports fail this time */
|
||||
orig_port = server->addr.sockAddr.sin_port;
|
||||
|
||||
/* do not retry on the same port we just failed on */
|
||||
if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
|
||||
server->addr.sockAddr.sin_port = htons(CIFS_PORT);
|
||||
rc = socket->ops->connect(socket,
|
||||
(struct sockaddr *)
|
||||
&server->addr.sockAddr,
|
||||
sizeof(struct sockaddr_in), 0);
|
||||
if (rc >= 0)
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
if (!connected) {
|
||||
server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
|
||||
rc = socket->ops->connect(socket, (struct sockaddr *)
|
||||
&server->addr.sockAddr,
|
||||
sizeof(struct sockaddr_in), 0);
|
||||
if (rc >= 0)
|
||||
connected = true;
|
||||
}
|
||||
|
||||
/* give up here - unless we want to retry on different
|
||||
protocol families some day */
|
||||
if (!connected) {
|
||||
if (orig_port)
|
||||
server->addr.sockAddr.sin_port = orig_port;
|
||||
cFYI(1, "Error %d connecting to server via ipv4", rc);
|
||||
rc = socket->ops->connect(socket, saddr, slen, 0);
|
||||
if (rc < 0) {
|
||||
cFYI(1, "Error %d connecting to server", rc);
|
||||
sock_release(socket);
|
||||
server->ssocket = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Eventually check for other socket options to change from
|
||||
* the default. sock_setsockopt not used because it expects
|
||||
@ -2226,7 +2312,7 @@ ipv4_connect(struct TCP_Server_Info *server)
|
||||
}
|
||||
|
||||
if (server->tcp_nodelay) {
|
||||
val = 1;
|
||||
int val = 1;
|
||||
rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
|
||||
(char *)&val, sizeof(val));
|
||||
if (rc)
|
||||
@ -2237,161 +2323,39 @@ ipv4_connect(struct TCP_Server_Info *server)
|
||||
socket->sk->sk_sndbuf,
|
||||
socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
|
||||
|
||||
/* send RFC1001 sessinit */
|
||||
if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
|
||||
/* some servers require RFC1001 sessinit before sending
|
||||
negprot - BB check reconnection in case where second
|
||||
sessinit is sent but no second negprot */
|
||||
struct rfc1002_session_packet *ses_init_buf;
|
||||
struct smb_hdr *smb_buf;
|
||||
ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
|
||||
GFP_KERNEL);
|
||||
if (ses_init_buf) {
|
||||
ses_init_buf->trailer.session_req.called_len = 32;
|
||||
if (server->server_RFC1001_name &&
|
||||
server->server_RFC1001_name[0] != 0)
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.called_name,
|
||||
server->server_RFC1001_name,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
else
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.called_name,
|
||||
DEFAULT_CIFS_CALLED_NAME,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
|
||||
ses_init_buf->trailer.session_req.calling_len = 32;
|
||||
|
||||
/* calling name ends in null (byte 16) from old smb
|
||||
convention. */
|
||||
if (server->workstation_RFC1001_name &&
|
||||
server->workstation_RFC1001_name[0] != 0)
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.calling_name,
|
||||
server->workstation_RFC1001_name,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
else
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.calling_name,
|
||||
"LINUX_CIFS_CLNT",
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
|
||||
ses_init_buf->trailer.session_req.scope1 = 0;
|
||||
ses_init_buf->trailer.session_req.scope2 = 0;
|
||||
smb_buf = (struct smb_hdr *)ses_init_buf;
|
||||
/* sizeof RFC1002_SESSION_REQUEST with no scope */
|
||||
smb_buf->smb_buf_length = 0x81000044;
|
||||
rc = smb_send(server, smb_buf, 0x44);
|
||||
kfree(ses_init_buf);
|
||||
msleep(1); /* RFC1001 layer in at least one server
|
||||
requires very short break before negprot
|
||||
presumably because not expecting negprot
|
||||
to follow so fast. This is a simple
|
||||
solution that works without
|
||||
complicating the code and causes no
|
||||
significant slowing down on mount
|
||||
for everyone else */
|
||||
}
|
||||
/* else the negprot may still work without this
|
||||
even though malloc failed */
|
||||
|
||||
}
|
||||
if (sport == htons(RFC1001_PORT))
|
||||
rc = ip_rfc1001_connect(server);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
ipv6_connect(struct TCP_Server_Info *server)
|
||||
ip_connect(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc = 0;
|
||||
int val;
|
||||
bool connected = false;
|
||||
__be16 orig_port = 0;
|
||||
struct socket *socket = server->ssocket;
|
||||
unsigned short int *sport;
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
|
||||
|
||||
if (socket == NULL) {
|
||||
rc = sock_create_kern(PF_INET6, SOCK_STREAM,
|
||||
IPPROTO_TCP, &socket);
|
||||
if (rc < 0) {
|
||||
cERROR(1, "Error %d creating ipv6 socket", rc);
|
||||
socket = NULL;
|
||||
return rc;
|
||||
}
|
||||
if (server->dstaddr.ss_family == AF_INET6)
|
||||
sport = &addr6->sin6_port;
|
||||
else
|
||||
sport = &addr->sin_port;
|
||||
|
||||
/* BB other socket options to set KEEPALIVE, NODELAY? */
|
||||
cFYI(1, "ipv6 Socket created");
|
||||
server->ssocket = socket;
|
||||
socket->sk->sk_allocation = GFP_NOFS;
|
||||
cifs_reclassify_socket6(socket);
|
||||
}
|
||||
if (*sport == 0) {
|
||||
int rc;
|
||||
|
||||
rc = bind_socket(server);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
/* try with 445 port at first */
|
||||
*sport = htons(CIFS_PORT);
|
||||
|
||||
/* user overrode default port */
|
||||
if (server->addr.sockAddr6.sin6_port) {
|
||||
rc = socket->ops->connect(socket,
|
||||
(struct sockaddr *) &server->addr.sockAddr6,
|
||||
sizeof(struct sockaddr_in6), 0);
|
||||
rc = generic_ip_connect(server);
|
||||
if (rc >= 0)
|
||||
connected = true;
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
/* save original port so we can retry user specified port
|
||||
later if fall back ports fail this time */
|
||||
|
||||
orig_port = server->addr.sockAddr6.sin6_port;
|
||||
/* do not retry on the same port we just failed on */
|
||||
if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
|
||||
server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
|
||||
rc = socket->ops->connect(socket, (struct sockaddr *)
|
||||
&server->addr.sockAddr6,
|
||||
sizeof(struct sockaddr_in6), 0);
|
||||
if (rc >= 0)
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
if (!connected) {
|
||||
server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
|
||||
rc = socket->ops->connect(socket, (struct sockaddr *)
|
||||
&server->addr.sockAddr6,
|
||||
sizeof(struct sockaddr_in6), 0);
|
||||
if (rc >= 0)
|
||||
connected = true;
|
||||
}
|
||||
|
||||
/* give up here - unless we want to retry on different
|
||||
protocol families some day */
|
||||
if (!connected) {
|
||||
if (orig_port)
|
||||
server->addr.sockAddr6.sin6_port = orig_port;
|
||||
cFYI(1, "Error %d connecting to server via ipv6", rc);
|
||||
sock_release(socket);
|
||||
server->ssocket = NULL;
|
||||
return rc;
|
||||
|
||||
/* if it failed, try with 139 port */
|
||||
*sport = htons(RFC1001_PORT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Eventually check for other socket options to change from
|
||||
* the default. sock_setsockopt not used because it expects
|
||||
* user space buffer
|
||||
*/
|
||||
socket->sk->sk_rcvtimeo = 7 * HZ;
|
||||
socket->sk->sk_sndtimeo = 5 * HZ;
|
||||
|
||||
if (server->tcp_nodelay) {
|
||||
val = 1;
|
||||
rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
|
||||
(char *)&val, sizeof(val));
|
||||
if (rc)
|
||||
cFYI(1, "set TCP_NODELAY socket option error %d", rc);
|
||||
}
|
||||
|
||||
server->ssocket = socket;
|
||||
|
||||
return rc;
|
||||
return generic_ip_connect(server);
|
||||
}
|
||||
|
||||
void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
|
||||
|
@ -293,10 +293,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
|
||||
current->tgid);
|
||||
} else {
|
||||
/* BB implement mode setting via Windows security
|
||||
descriptors e.g. */
|
||||
|
213
fs/cifs/file.c
213
fs/cifs/file.c
@ -104,53 +104,6 @@ static inline int cifs_get_disposition(unsigned int flags)
|
||||
return FILE_OPEN;
|
||||
}
|
||||
|
||||
static inline int cifs_open_inode_helper(struct inode *inode,
|
||||
struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf,
|
||||
char *full_path, int xid)
|
||||
{
|
||||
struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
|
||||
struct timespec temp;
|
||||
int rc;
|
||||
|
||||
if (pCifsInode->clientCanCacheRead) {
|
||||
/* we have the inode open somewhere else
|
||||
no need to discard cache data */
|
||||
goto client_can_cache;
|
||||
}
|
||||
|
||||
/* BB need same check in cifs_create too? */
|
||||
/* if not oplocked, invalidate inode pages if mtime or file
|
||||
size changed */
|
||||
temp = cifs_NTtimeToUnix(buf->LastWriteTime);
|
||||
if (timespec_equal(&inode->i_mtime, &temp) &&
|
||||
(inode->i_size ==
|
||||
(loff_t)le64_to_cpu(buf->EndOfFile))) {
|
||||
cFYI(1, "inode unchanged on server");
|
||||
} else {
|
||||
if (inode->i_mapping) {
|
||||
/* BB no need to lock inode until after invalidate
|
||||
since namei code should already have it locked? */
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
}
|
||||
cFYI(1, "invalidating remote inode since open detected it "
|
||||
"changed");
|
||||
invalidate_remote_inode(inode);
|
||||
}
|
||||
|
||||
client_can_cache:
|
||||
if (pTcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
|
||||
xid);
|
||||
else
|
||||
rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
|
||||
xid, NULL);
|
||||
|
||||
cifs_set_oplock_level(pCifsInode, oplock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||
struct super_block *sb, int mode, unsigned int f_flags,
|
||||
__u32 *poplock, __u16 *pnetfid, int xid)
|
||||
@ -213,6 +166,76 @@ posix_open_ret:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
|
||||
struct cifsTconInfo *tcon, unsigned int f_flags, __u32 *poplock,
|
||||
__u16 *pnetfid, int xid)
|
||||
{
|
||||
int rc;
|
||||
int desiredAccess;
|
||||
int disposition;
|
||||
FILE_ALL_INFO *buf;
|
||||
|
||||
desiredAccess = cifs_convert_flags(f_flags);
|
||||
|
||||
/*********************************************************************
|
||||
* open flag mapping table:
|
||||
*
|
||||
* POSIX Flag CIFS Disposition
|
||||
* ---------- ----------------
|
||||
* O_CREAT FILE_OPEN_IF
|
||||
* O_CREAT | O_EXCL FILE_CREATE
|
||||
* O_CREAT | O_TRUNC FILE_OVERWRITE_IF
|
||||
* O_TRUNC FILE_OVERWRITE
|
||||
* none of the above FILE_OPEN
|
||||
*
|
||||
* Note that there is not a direct match between disposition
|
||||
* FILE_SUPERSEDE (ie create whether or not file exists although
|
||||
* O_CREAT | O_TRUNC is similar but truncates the existing
|
||||
* file rather than creating a new file as FILE_SUPERSEDE does
|
||||
* (which uses the attributes / metadata passed in on open call)
|
||||
*?
|
||||
*? O_SYNC is a reasonable match to CIFS writethrough flag
|
||||
*? and the read write flags match reasonably. O_LARGEFILE
|
||||
*? is irrelevant because largefile support is always used
|
||||
*? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
|
||||
* O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
|
||||
*********************************************************************/
|
||||
|
||||
disposition = cifs_get_disposition(f_flags);
|
||||
|
||||
/* BB pass O_SYNC flag through on file attributes .. BB */
|
||||
|
||||
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (tcon->ses->capabilities & CAP_NT_SMBS)
|
||||
rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
||||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
else
|
||||
rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
||||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (tcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
|
||||
xid);
|
||||
else
|
||||
rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
|
||||
xid, pnetfid);
|
||||
|
||||
out:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct cifsFileInfo *
|
||||
cifs_new_fileinfo(__u16 fileHandle, struct file *file,
|
||||
struct tcon_link *tlink, __u32 oplock)
|
||||
@ -317,10 +340,8 @@ int cifs_open(struct inode *inode, struct file *file)
|
||||
struct cifsFileInfo *pCifsFile = NULL;
|
||||
struct cifsInodeInfo *pCifsInode;
|
||||
char *full_path = NULL;
|
||||
int desiredAccess;
|
||||
int disposition;
|
||||
bool posix_open_ok = false;
|
||||
__u16 netfid;
|
||||
FILE_ALL_INFO *buf = NULL;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
@ -358,17 +379,7 @@ int cifs_open(struct inode *inode, struct file *file)
|
||||
file->f_flags, &oplock, &netfid, xid);
|
||||
if (rc == 0) {
|
||||
cFYI(1, "posix open succeeded");
|
||||
|
||||
pCifsFile = cifs_new_fileinfo(netfid, file, tlink,
|
||||
oplock);
|
||||
if (pCifsFile == NULL) {
|
||||
CIFSSMBClose(xid, tcon, netfid);
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
|
||||
cifs_fscache_set_inode_cookie(inode, file);
|
||||
|
||||
goto out;
|
||||
posix_open_ok = true;
|
||||
} else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
|
||||
if (tcon->ses->serverNOS)
|
||||
cERROR(1, "server %s of type %s returned"
|
||||
@ -385,85 +396,25 @@ int cifs_open(struct inode *inode, struct file *file)
|
||||
or DFS errors */
|
||||
}
|
||||
|
||||
desiredAccess = cifs_convert_flags(file->f_flags);
|
||||
|
||||
/*********************************************************************
|
||||
* open flag mapping table:
|
||||
*
|
||||
* POSIX Flag CIFS Disposition
|
||||
* ---------- ----------------
|
||||
* O_CREAT FILE_OPEN_IF
|
||||
* O_CREAT | O_EXCL FILE_CREATE
|
||||
* O_CREAT | O_TRUNC FILE_OVERWRITE_IF
|
||||
* O_TRUNC FILE_OVERWRITE
|
||||
* none of the above FILE_OPEN
|
||||
*
|
||||
* Note that there is not a direct match between disposition
|
||||
* FILE_SUPERSEDE (ie create whether or not file exists although
|
||||
* O_CREAT | O_TRUNC is similar but truncates the existing
|
||||
* file rather than creating a new file as FILE_SUPERSEDE does
|
||||
* (which uses the attributes / metadata passed in on open call)
|
||||
*?
|
||||
*? O_SYNC is a reasonable match to CIFS writethrough flag
|
||||
*? and the read write flags match reasonably. O_LARGEFILE
|
||||
*? is irrelevant because largefile support is always used
|
||||
*? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
|
||||
* O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
|
||||
*********************************************************************/
|
||||
|
||||
disposition = cifs_get_disposition(file->f_flags);
|
||||
|
||||
/* BB pass O_SYNC flag through on file attributes .. BB */
|
||||
|
||||
/* Also refresh inode by passing in file_info buf returned by SMBOpen
|
||||
and calling get_inode_info with returned buf (at least helps
|
||||
non-Unix server case) */
|
||||
|
||||
/* BB we can not do this if this is the second open of a file
|
||||
and the first handle has writebehind data, we might be
|
||||
able to simply do a filemap_fdatawrite/filemap_fdatawait first */
|
||||
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||
if (!buf) {
|
||||
rc = -ENOMEM;
|
||||
if (!posix_open_ok) {
|
||||
rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
|
||||
file->f_flags, &oplock, &netfid, xid);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tcon->ses->capabilities & CAP_NT_SMBS)
|
||||
rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
||||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
else
|
||||
rc = -EIO; /* no NT SMB support fall into legacy open below */
|
||||
|
||||
if (rc == -EIO) {
|
||||
/* Old server, try legacy style OpenX */
|
||||
rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
||||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
if (rc) {
|
||||
cFYI(1, "cifs_open returned 0x%x", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
|
||||
if (pCifsFile == NULL) {
|
||||
CIFSSMBClose(xid, tcon, netfid);
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cifs_fscache_set_inode_cookie(inode, file);
|
||||
|
||||
if (oplock & CIFS_CREATE_ACTION) {
|
||||
if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
|
||||
/* time to set mode which we can not set earlier due to
|
||||
problems creating new read-only files */
|
||||
if (tcon->unix_ext) {
|
||||
struct cifs_unix_set_info_args args = {
|
||||
.mode = inode->i_mode,
|
||||
.uid = NO_CHANGE_64,
|
||||
@ -473,15 +424,11 @@ int cifs_open(struct inode *inode, struct file *file)
|
||||
.mtime = NO_CHANGE_64,
|
||||
.device = 0,
|
||||
};
|
||||
CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
|
||||
pCifsFile->pid);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(buf);
|
||||
kfree(full_path);
|
||||
FreeXid(xid);
|
||||
cifs_put_tlink(tlink);
|
||||
|
@ -518,6 +518,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
|
||||
|
||||
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
||||
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
||||
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
|
||||
|
||||
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||
fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
|
||||
@ -779,6 +780,10 @@ cifs_find_inode(struct inode *inode, void *opaque)
|
||||
if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
|
||||
return 0;
|
||||
|
||||
/* use createtime like an i_generation field */
|
||||
if (CIFS_I(inode)->createtime != fattr->cf_createtime)
|
||||
return 0;
|
||||
|
||||
/* don't match inode of different type */
|
||||
if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
|
||||
return 0;
|
||||
@ -796,6 +801,7 @@ cifs_init_inode(struct inode *inode, void *opaque)
|
||||
struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
|
||||
|
||||
CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
|
||||
CIFS_I(inode)->createtime = fattr->cf_createtime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -160,6 +160,7 @@ cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
|
||||
fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes);
|
||||
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
||||
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
||||
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
|
||||
fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
|
||||
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
|
||||
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
|
||||
|
@ -420,7 +420,6 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
/* BB Move to ntlmssp.c eventually */
|
||||
|
||||
/* We do not malloc the blob, it is passed in pbuffer, because
|
||||
@ -431,13 +430,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
|
||||
NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer;
|
||||
__u32 flags;
|
||||
|
||||
memset(pbuffer, 0, sizeof(NEGOTIATE_MESSAGE));
|
||||
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
|
||||
sec_blob->MessageType = NtLmNegotiate;
|
||||
|
||||
/* BB is NTLMV2 session security format easier to use here? */
|
||||
flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET |
|
||||
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
|
||||
NTLMSSP_NEGOTIATE_NTLM;
|
||||
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
|
||||
if (ses->server->secMode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
|
||||
flags |= NTLMSSP_NEGOTIATE_SIGN;
|
||||
@ -446,7 +446,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
|
||||
NTLMSSP_NEGOTIATE_EXTENDED_SEC;
|
||||
}
|
||||
|
||||
sec_blob->NegotiateFlags |= cpu_to_le32(flags);
|
||||
sec_blob->NegotiateFlags = cpu_to_le32(flags);
|
||||
|
||||
sec_blob->WorkstationName.BufferOffset = 0;
|
||||
sec_blob->WorkstationName.Length = 0;
|
||||
@ -477,7 +477,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
|
||||
flags = NTLMSSP_NEGOTIATE_56 |
|
||||
NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
|
||||
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
|
||||
NTLMSSP_NEGOTIATE_NTLM;
|
||||
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
|
||||
if (ses->server->secMode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
|
||||
flags |= NTLMSSP_NEGOTIATE_SIGN;
|
||||
@ -485,7 +485,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
|
||||
flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
||||
|
||||
tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE);
|
||||
sec_blob->NegotiateFlags |= cpu_to_le32(flags);
|
||||
sec_blob->NegotiateFlags = cpu_to_le32(flags);
|
||||
|
||||
sec_blob->LmChallengeResponse.BufferOffset =
|
||||
cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE));
|
||||
@ -544,8 +544,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
|
||||
sec_blob->WorkstationName.MaximumLength = 0;
|
||||
tmp += 2;
|
||||
|
||||
if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
|
||||
!calc_seckey(ses)) {
|
||||
if (((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) ||
|
||||
(ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
|
||||
&& !calc_seckey(ses)) {
|
||||
memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
|
||||
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
|
||||
sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
|
||||
@ -563,17 +564,6 @@ setup_ntlmv2_ret:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB,
|
||||
struct cifsSesInfo *ses)
|
||||
{
|
||||
build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses);
|
||||
pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
||||
const struct nls_table *nls_cp)
|
||||
@ -814,9 +804,7 @@ ssetup_ntlmssp_authenticate:
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
#endif /* CONFIG_CIFS_UPCALL */
|
||||
} else {
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if (type == RawNTLMSSP) {
|
||||
} else if (type == RawNTLMSSP) {
|
||||
if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
||||
cERROR(1, "NTLMSSP requires Unicode support");
|
||||
rc = -ENOSYS;
|
||||
@ -827,21 +815,26 @@ ssetup_ntlmssp_authenticate:
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
capabilities |= CAP_EXTENDED_SECURITY;
|
||||
pSMB->req.Capabilities |= cpu_to_le32(capabilities);
|
||||
if (phase == NtLmNegotiate) {
|
||||
setup_ntlmssp_neg_req(pSMB, ses);
|
||||
switch(phase) {
|
||||
case NtLmNegotiate:
|
||||
build_ntlmssp_negotiate_blob(
|
||||
pSMB->req.SecurityBlob, ses);
|
||||
iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
|
||||
iov[1].iov_base = &pSMB->req.SecurityBlob[0];
|
||||
} else if (phase == NtLmAuthenticate) {
|
||||
/* 5 is an empirical value, large enought to
|
||||
* hold authenticate message, max 10 of
|
||||
* av paris, doamin,user,workstation mames,
|
||||
* flags etc..
|
||||
iov[1].iov_base = pSMB->req.SecurityBlob;
|
||||
pSMB->req.SecurityBlobLength =
|
||||
cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
|
||||
break;
|
||||
case NtLmAuthenticate:
|
||||
/*
|
||||
* 5 is an empirical value, large enough to hold
|
||||
* authenticate message plus max 10 of av paris,
|
||||
* domain, user, workstation names, flags, etc.
|
||||
*/
|
||||
ntlmsspblob = kmalloc(
|
||||
ntlmsspblob = kzalloc(
|
||||
5*sizeof(struct _AUTHENTICATE_MESSAGE),
|
||||
GFP_KERNEL);
|
||||
if (!ntlmsspblob) {
|
||||
cERROR(1, "Can't allocate NTLMSSP");
|
||||
cERROR(1, "Can't allocate NTLMSSP blob");
|
||||
rc = -ENOMEM;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
@ -852,13 +845,15 @@ ssetup_ntlmssp_authenticate:
|
||||
goto ssetup_exit;
|
||||
iov[1].iov_len = blob_len;
|
||||
iov[1].iov_base = ntlmsspblob;
|
||||
pSMB->req.SecurityBlobLength =
|
||||
cpu_to_le16(blob_len);
|
||||
/* Make sure that we tell the server that we
|
||||
are using the uid that it just gave us back
|
||||
on the response (challenge) */
|
||||
pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
|
||||
/*
|
||||
* Make sure that we tell the server that we are using
|
||||
* the uid that it just gave us back on the response
|
||||
* (challenge)
|
||||
*/
|
||||
smb_buf->Uid = ses->Suid;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
cERROR(1, "invalid phase %d", phase);
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
@ -874,12 +869,6 @@ ssetup_ntlmssp_authenticate:
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
#else
|
||||
cERROR(1, "secType %d not supported!", type);
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
#endif
|
||||
}
|
||||
|
||||
iov[2].iov_base = str_area;
|
||||
iov[2].iov_len = (long) bcc_ptr - (long) str_area;
|
||||
|
@ -119,7 +119,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
|
||||
if (ssocket == NULL)
|
||||
return -ENOTSOCK; /* BB eventually add reconnect code here */
|
||||
|
||||
smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr;
|
||||
smb_msg.msg_name = (struct sockaddr *) &server->dstaddr;
|
||||
smb_msg.msg_namelen = sizeof(struct sockaddr);
|
||||
smb_msg.msg_control = NULL;
|
||||
smb_msg.msg_controllen = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user