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] DFS build fixes [CIFS] DFS support: provide shrinkable mounts [CIFS] Do not log path names in lookup errors [CIFS] DFS support patchset: Added mountdata [CIFS] Forgot to add two new files from previous commit [CIFS] DNS name resolution helper upcall for cifs [CIFS] fix checkpatch warnings in fs/cifs/inode.c [CIFS] hold ses sem on tcp session reconnect during mount [CIFS] Allow setting mode via cifs acl [CIFS] fix unicode string alignment in SPNEGO setup [CIFS] cifs_partialpagewrite() cleanup [CIFS] use krb5 session key from first SMB session after a NegProt [CIFS] redo existing session setup if needed in cifs_mount [CIFS] Only dump SPNEGO key if CONFIG_CIFS_DEBUG2 is set [CIFS] fix SetEA failure to some Samba versions
This commit is contained in:
commit
ef3f2de2b5
23 changed files with 1051 additions and 96 deletions
37
fs/Kconfig
37
fs/Kconfig
|
@ -1899,13 +1899,15 @@ config CIFS
|
||||||
file servers such as Windows 2000 (including Windows 2003, NT 4
|
file servers such as Windows 2000 (including Windows 2003, NT 4
|
||||||
and Windows XP) as well by Samba (which provides excellent CIFS
|
and Windows XP) as well by Samba (which provides excellent CIFS
|
||||||
server support for Linux and many other operating systems). Limited
|
server support for Linux and many other operating systems). Limited
|
||||||
support for OS/2 and Windows ME and similar servers is provided as well.
|
support for OS/2 and Windows ME and similar servers is provided as
|
||||||
|
well.
|
||||||
|
|
||||||
The intent of the cifs module is to provide an advanced
|
The cifs module provides an advanced network file system
|
||||||
network file system client for mounting to CIFS compliant servers,
|
client for mounting to CIFS compliant servers. It includes
|
||||||
including support for dfs (hierarchical name space), secure per-user
|
support for DFS (hierarchical name space), secure per-user
|
||||||
session establishment, safe distributed caching (oplock), optional
|
session establishment via Kerberos or NTLM or NTLMv2,
|
||||||
packet signing, Unicode and other internationalization improvements.
|
safe distributed caching (oplock), optional packet
|
||||||
|
signing, Unicode and other internationalization improvements.
|
||||||
If you need to mount to Samba or Windows from this machine, say Y.
|
If you need to mount to Samba or Windows from this machine, say Y.
|
||||||
|
|
||||||
config CIFS_STATS
|
config CIFS_STATS
|
||||||
|
@ -1937,7 +1939,8 @@ config CIFS_WEAK_PW_HASH
|
||||||
(since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
|
(since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
|
||||||
security mechanisms. These hash the password more securely
|
security mechanisms. These hash the password more securely
|
||||||
than the mechanisms used in the older LANMAN version of the
|
than the mechanisms used in the older LANMAN version of the
|
||||||
SMB protocol needed to establish sessions with old SMB servers.
|
SMB protocol but LANMAN based authentication is needed to
|
||||||
|
establish sessions with some old SMB servers.
|
||||||
|
|
||||||
Enabling this option allows the cifs module to mount to older
|
Enabling this option allows the cifs module to mount to older
|
||||||
LANMAN based servers such as OS/2 and Windows 95, but such
|
LANMAN based servers such as OS/2 and Windows 95, but such
|
||||||
|
@ -1945,8 +1948,8 @@ config CIFS_WEAK_PW_HASH
|
||||||
security mechanisms if you are on a public network. Unless you
|
security mechanisms if you are on a public network. Unless you
|
||||||
have a need to access old SMB servers (and are on a private
|
have a need to access old SMB servers (and are on a private
|
||||||
network) you probably want to say N. Even if this support
|
network) you probably want to say N. Even if this support
|
||||||
is enabled in the kernel build, they will not be used
|
is enabled in the kernel build, LANMAN authentication will not be
|
||||||
automatically. At runtime LANMAN mounts are disabled but
|
used automatically. At runtime LANMAN mounts are disabled but
|
||||||
can be set to required (or optional) either in
|
can be set to required (or optional) either in
|
||||||
/proc/fs/cifs (see fs/cifs/README for more detail) or via an
|
/proc/fs/cifs (see fs/cifs/README for more detail) or via an
|
||||||
option on the mount command. This support is disabled by
|
option on the mount command. This support is disabled by
|
||||||
|
@ -2012,12 +2015,22 @@ config CIFS_UPCALL
|
||||||
depends on CIFS_EXPERIMENTAL
|
depends on CIFS_EXPERIMENTAL
|
||||||
depends on KEYS
|
depends on KEYS
|
||||||
help
|
help
|
||||||
Enables an upcall mechanism for CIFS which will be used to contact
|
Enables an upcall mechanism for CIFS which accesses
|
||||||
userspace helper utilities to provide SPNEGO packaged Kerberos
|
userspace helper utilities to provide SPNEGO packaged (RFC 4178)
|
||||||
tickets which are needed to mount to certain secure servers
|
Kerberos tickets which are needed to mount to certain secure servers
|
||||||
(for which more secure Kerberos authentication is required). If
|
(for which more secure Kerberos authentication is required). If
|
||||||
unsure, say N.
|
unsure, say N.
|
||||||
|
|
||||||
|
config CIFS_DFS_UPCALL
|
||||||
|
bool "DFS feature support (EXPERIMENTAL)"
|
||||||
|
depends on CIFS_EXPERIMENTAL
|
||||||
|
depends on KEYS
|
||||||
|
help
|
||||||
|
Enables an upcall mechanism for CIFS which contacts userspace
|
||||||
|
helper utilities to provide server name resolution (host names to
|
||||||
|
IP addresses) which is needed for implicit mounts of DFS junction
|
||||||
|
points. If unsure, say N.
|
||||||
|
|
||||||
config NCP_FS
|
config NCP_FS
|
||||||
tristate "NCP file system support (to mount NetWare volumes)"
|
tristate "NCP file system support (to mount NetWare volumes)"
|
||||||
depends on IPX!=n || INET
|
depends on IPX!=n || INET
|
||||||
|
|
|
@ -3,7 +3,10 @@ Version 1.52
|
||||||
Fix oops on second mount to server when null auth is used.
|
Fix oops on second mount to server when null auth is used.
|
||||||
Enable experimental Kerberos support. Return writebehind errors on flush
|
Enable experimental Kerberos support. Return writebehind errors on flush
|
||||||
and sync so that events like out of disk space get reported properly on
|
and sync so that events like out of disk space get reported properly on
|
||||||
cached files.
|
cached files. Fix setxattr failure to certain Samba versions. Fix mount
|
||||||
|
of second share to disconnected server session (autoreconnect on this).
|
||||||
|
Add ability to modify cifs acls for handling chmod (when mounted with
|
||||||
|
cifsacl flag).
|
||||||
|
|
||||||
Version 1.51
|
Version 1.51
|
||||||
------------
|
------------
|
||||||
|
|
|
@ -9,3 +9,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
|
||||||
readdir.o ioctl.o sess.o export.o cifsacl.o
|
readdir.o ioctl.o sess.o export.o cifsacl.o
|
||||||
|
|
||||||
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
|
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
|
||||||
|
|
||||||
|
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
|
||||||
|
|
|
@ -56,7 +56,8 @@ the CIFS VFS web site) copy it to the same directory in which mount.smbfs and
|
||||||
similar files reside (usually /sbin). Although the helper software is not
|
similar files reside (usually /sbin). Although the helper software is not
|
||||||
required, mount.cifs is recommended. Eventually the Samba 3.0 utility program
|
required, mount.cifs is recommended. Eventually the Samba 3.0 utility program
|
||||||
"net" may also be helpful since it may someday provide easier mount syntax for
|
"net" may also be helpful since it may someday provide easier mount syntax for
|
||||||
users who are used to Windows e.g. net use <mount point> <UNC name or cifs URL>
|
users who are used to Windows e.g.
|
||||||
|
net use <mount point> <UNC name or cifs URL>
|
||||||
Note that running the Winbind pam/nss module (logon service) on all of your
|
Note that running the Winbind pam/nss module (logon service) on all of your
|
||||||
Linux clients is useful in mapping Uids and Gids consistently across the
|
Linux clients is useful in mapping Uids and Gids consistently across the
|
||||||
domain to the proper network user. The mount.cifs mount helper can be
|
domain to the proper network user. The mount.cifs mount helper can be
|
||||||
|
@ -248,7 +249,7 @@ A partial list of the supported mount options follows:
|
||||||
the CIFS session.
|
the CIFS session.
|
||||||
password The user password. If the mount helper is
|
password The user password. If the mount helper is
|
||||||
installed, the user will be prompted for password
|
installed, the user will be prompted for password
|
||||||
if it is not supplied.
|
if not supplied.
|
||||||
ip The ip address of the target server
|
ip The ip address of the target server
|
||||||
unc The target server Universal Network Name (export) to
|
unc The target server Universal Network Name (export) to
|
||||||
mount.
|
mount.
|
||||||
|
@ -283,7 +284,7 @@ A partial list of the supported mount options follows:
|
||||||
can be enabled by specifying file_mode and dir_mode on
|
can be enabled by specifying file_mode and dir_mode on
|
||||||
the client. Note that the mount.cifs helper must be
|
the client. Note that the mount.cifs helper must be
|
||||||
at version 1.10 or higher to support specifying the uid
|
at version 1.10 or higher to support specifying the uid
|
||||||
(or gid) in non-numberic form.
|
(or gid) in non-numeric form.
|
||||||
gid Set the default gid for inodes (similar to above).
|
gid Set the default gid for inodes (similar to above).
|
||||||
file_mode If CIFS Unix extensions are not supported by the server
|
file_mode If CIFS Unix extensions are not supported by the server
|
||||||
this overrides the default mode for file inodes.
|
this overrides the default mode for file inodes.
|
||||||
|
@ -417,9 +418,10 @@ A partial list of the supported mount options follows:
|
||||||
acl Allow setfacl and getfacl to manage posix ACLs if server
|
acl Allow setfacl and getfacl to manage posix ACLs if server
|
||||||
supports them. (default)
|
supports them. (default)
|
||||||
noacl Do not allow setfacl and getfacl calls on this mount
|
noacl Do not allow setfacl and getfacl calls on this mount
|
||||||
user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended
|
user_xattr Allow getting and setting user xattrs (those attributes whose
|
||||||
attributes) to the server (default) e.g. via setfattr
|
name begins with "user." or "os2.") as OS/2 EAs (extended
|
||||||
and getfattr utilities.
|
attributes) to the server. This allows support of the
|
||||||
|
setfattr and getfattr utilities. (default)
|
||||||
nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs
|
nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs
|
||||||
mapchars Translate six of the seven reserved characters (not backslash)
|
mapchars Translate six of the seven reserved characters (not backslash)
|
||||||
*?<>|:
|
*?<>|:
|
||||||
|
@ -434,6 +436,7 @@ A partial list of the supported mount options follows:
|
||||||
nomapchars Do not translate any of these seven characters (default).
|
nomapchars Do not translate any of these seven characters (default).
|
||||||
nocase Request case insensitive path name matching (case
|
nocase Request case insensitive path name matching (case
|
||||||
sensitive is the default if the server suports it).
|
sensitive is the default if the server suports it).
|
||||||
|
(mount option "ignorecase" is identical to "nocase")
|
||||||
posixpaths If CIFS Unix extensions are supported, attempt to
|
posixpaths If CIFS Unix extensions are supported, attempt to
|
||||||
negotiate posix path name support which allows certain
|
negotiate posix path name support which allows certain
|
||||||
characters forbidden in typical CIFS filenames, without
|
characters forbidden in typical CIFS filenames, without
|
||||||
|
@ -485,6 +488,9 @@ A partial list of the supported mount options follows:
|
||||||
ntlmv2i Use NTLMv2 password hashing with packet signing
|
ntlmv2i Use NTLMv2 password hashing with packet signing
|
||||||
lanman (if configured in kernel config) use older
|
lanman (if configured in kernel config) use older
|
||||||
lanman hash
|
lanman hash
|
||||||
|
hard Retry file operations if server is not responding
|
||||||
|
soft Limit retries to unresponsive servers (usually only
|
||||||
|
one retry) before returning an error. (default)
|
||||||
|
|
||||||
The mount.cifs mount helper also accepts a few mount options before -o
|
The mount.cifs mount helper also accepts a few mount options before -o
|
||||||
including:
|
including:
|
||||||
|
@ -535,8 +541,8 @@ SecurityFlags Flags which control security negotiation and
|
||||||
must use NTLM 0x02002
|
must use NTLM 0x02002
|
||||||
may use NTLMv2 0x00004
|
may use NTLMv2 0x00004
|
||||||
must use NTLMv2 0x04004
|
must use NTLMv2 0x04004
|
||||||
may use Kerberos security (not implemented yet) 0x00008
|
may use Kerberos security 0x00008
|
||||||
must use Kerberos (not implemented yet) 0x08008
|
must use Kerberos 0x08008
|
||||||
may use lanman (weak) password hash 0x00010
|
may use lanman (weak) password hash 0x00010
|
||||||
must use lanman password hash 0x10010
|
must use lanman password hash 0x10010
|
||||||
may use plaintext passwords 0x00020
|
may use plaintext passwords 0x00020
|
||||||
|
@ -626,6 +632,6 @@ returned success.
|
||||||
|
|
||||||
Also note that "cat /proc/fs/cifs/DebugData" will display information about
|
Also note that "cat /proc/fs/cifs/DebugData" will display information about
|
||||||
the active sessions and the shares that are mounted.
|
the active sessions and the shares that are mounted.
|
||||||
Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled
|
Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is
|
||||||
but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
|
on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
|
||||||
LANMAN support do not require this helpr.
|
LANMAN support do not require this helper.
|
||||||
|
|
14
fs/cifs/TODO
14
fs/cifs/TODO
|
@ -1,4 +1,4 @@
|
||||||
Version 1.49 April 26, 2007
|
Version 1.52 January 3, 2008
|
||||||
|
|
||||||
A Partial List of Missing Features
|
A Partial List of Missing Features
|
||||||
==================================
|
==================================
|
||||||
|
@ -16,16 +16,14 @@ SecurityDescriptors
|
||||||
c) Better pam/winbind integration (e.g. to handle uid mapping
|
c) Better pam/winbind integration (e.g. to handle uid mapping
|
||||||
better)
|
better)
|
||||||
|
|
||||||
d) Verify that Kerberos signing works
|
d) Cleanup now unneeded SessSetup code in
|
||||||
|
|
||||||
e) Cleanup now unneeded SessSetup code in
|
|
||||||
fs/cifs/connect.c and add back in NTLMSSP code if any servers
|
fs/cifs/connect.c and add back in NTLMSSP code if any servers
|
||||||
need it
|
need it
|
||||||
|
|
||||||
f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup
|
e) ms-dfs and ms-dfs host name resolution cleanup
|
||||||
used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
|
|
||||||
and raw NTLMSSP already. This is important when enabling
|
f) fix NTLMv2 signing when two mounts with different users to same
|
||||||
extended security and mounting to Windows 2003 Servers
|
server.
|
||||||
|
|
||||||
g) Directory entry caching relies on a 1 second timer, rather than
|
g) Directory entry caching relies on a 1 second timer, rather than
|
||||||
using FindNotify or equivalent. - (started)
|
using FindNotify or equivalent. - (started)
|
||||||
|
|
377
fs/cifs/cifs_dfs_ref.c
Normal file
377
fs/cifs/cifs_dfs_ref.c
Normal file
|
@ -0,0 +1,377 @@
|
||||||
|
/*
|
||||||
|
* Contains the CIFS DFS referral mounting routines used for handling
|
||||||
|
* traversal via DFS junction point
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Igor Mammedov
|
||||||
|
* Copyright (C) International Business Machines Corp., 2008
|
||||||
|
* Author(s): Igor Mammedov (niallain@gmail.com)
|
||||||
|
* Steve French (sfrench@us.ibm.com)
|
||||||
|
* 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 the Free Software Foundation; either version
|
||||||
|
* 2 of the License, or (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/dcache.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
|
#include <linux/vfs.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include "cifsglob.h"
|
||||||
|
#include "cifsproto.h"
|
||||||
|
#include "cifsfs.h"
|
||||||
|
#include "dns_resolve.h"
|
||||||
|
#include "cifs_debug.h"
|
||||||
|
|
||||||
|
LIST_HEAD(cifs_dfs_automount_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DFS functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
|
||||||
|
{
|
||||||
|
mark_mounts_for_expiry(&cifs_dfs_automount_list);
|
||||||
|
mark_mounts_for_expiry(&cifs_dfs_automount_list);
|
||||||
|
shrink_submounts(vfsmnt, &cifs_dfs_automount_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cifs_get_share_name - extracts share name from UNC
|
||||||
|
* @node_name: pointer to UNC string
|
||||||
|
*
|
||||||
|
* Extracts sharename form full UNC.
|
||||||
|
* i.e. strips from UNC trailing path that is not part of share
|
||||||
|
* name and fixup missing '\' in the begining of DFS node refferal
|
||||||
|
* if neccessary.
|
||||||
|
* Returns pointer to share name on success or NULL on error.
|
||||||
|
* Caller is responsible for freeing returned string.
|
||||||
|
*/
|
||||||
|
static char *cifs_get_share_name(const char *node_name)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char *UNC;
|
||||||
|
char *pSep;
|
||||||
|
|
||||||
|
len = strlen(node_name);
|
||||||
|
UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!UNC)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* get share name and server name */
|
||||||
|
if (node_name[1] != '\\') {
|
||||||
|
UNC[0] = '\\';
|
||||||
|
strncpy(UNC+1, node_name, len);
|
||||||
|
len++;
|
||||||
|
UNC[len] = 0;
|
||||||
|
} else {
|
||||||
|
strncpy(UNC, node_name, len);
|
||||||
|
UNC[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find server name end */
|
||||||
|
pSep = memchr(UNC+2, '\\', len-2);
|
||||||
|
if (!pSep) {
|
||||||
|
cERROR(1, ("%s: no server name end in node name: %s",
|
||||||
|
__FUNCTION__, node_name));
|
||||||
|
kfree(UNC);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find sharename end */
|
||||||
|
pSep++;
|
||||||
|
pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
|
||||||
|
if (!pSep) {
|
||||||
|
cERROR(1, ("%s:2 cant find share name in node name: %s",
|
||||||
|
__FUNCTION__, node_name));
|
||||||
|
kfree(UNC);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* trim path up to sharename end
|
||||||
|
* * now we have share name in UNC */
|
||||||
|
*pSep = 0;
|
||||||
|
|
||||||
|
return UNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compose_mount_options - creates mount options for refferral
|
||||||
|
* @sb_mountdata: parent/root DFS mount options (template)
|
||||||
|
* @ref_unc: refferral server UNC
|
||||||
|
* @devname: pointer for saving device name
|
||||||
|
*
|
||||||
|
* creates mount options for submount based on template options sb_mountdata
|
||||||
|
* and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
|
||||||
|
*
|
||||||
|
* Returns: pointer to new mount options or ERR_PTR.
|
||||||
|
* Caller is responcible for freeing retunrned value if it is not error.
|
||||||
|
*/
|
||||||
|
static char *compose_mount_options(const char *sb_mountdata,
|
||||||
|
const char *ref_unc,
|
||||||
|
char **devname)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
char *mountdata;
|
||||||
|
int md_len;
|
||||||
|
char *tkn_e;
|
||||||
|
char *srvIP = NULL;
|
||||||
|
char sep = ',';
|
||||||
|
int off, noff;
|
||||||
|
|
||||||
|
if (sb_mountdata == NULL)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
*devname = cifs_get_share_name(ref_unc);
|
||||||
|
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
||||||
|
if (rc != 0) {
|
||||||
|
cERROR(1, ("%s: Failed to resolve server part of %s to IP",
|
||||||
|
__FUNCTION__, *devname));
|
||||||
|
mountdata = ERR_PTR(rc);
|
||||||
|
goto compose_mount_options_out;
|
||||||
|
}
|
||||||
|
md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3;
|
||||||
|
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
||||||
|
if (mountdata == NULL) {
|
||||||
|
mountdata = ERR_PTR(-ENOMEM);
|
||||||
|
goto compose_mount_options_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy all options except of unc,ip,prefixpath */
|
||||||
|
off = 0;
|
||||||
|
if (strncmp(sb_mountdata, "sep=", 4) == 0) {
|
||||||
|
sep = sb_mountdata[4];
|
||||||
|
strncpy(mountdata, sb_mountdata, 5);
|
||||||
|
off += 5;
|
||||||
|
}
|
||||||
|
while ((tkn_e = strchr(sb_mountdata+off, sep))) {
|
||||||
|
noff = (tkn_e - (sb_mountdata+off)) + 1;
|
||||||
|
if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) {
|
||||||
|
off += noff;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) {
|
||||||
|
off += noff;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) {
|
||||||
|
off += noff;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
strncat(mountdata, sb_mountdata+off, noff);
|
||||||
|
off += noff;
|
||||||
|
}
|
||||||
|
strcat(mountdata, sb_mountdata+off);
|
||||||
|
mountdata[md_len] = '\0';
|
||||||
|
|
||||||
|
/* copy new IP and ref share name */
|
||||||
|
strcat(mountdata, ",ip=");
|
||||||
|
strcat(mountdata, srvIP);
|
||||||
|
strcat(mountdata, ",unc=");
|
||||||
|
strcat(mountdata, *devname);
|
||||||
|
|
||||||
|
/* find & copy prefixpath */
|
||||||
|
tkn_e = strchr(ref_unc+2, '\\');
|
||||||
|
if (tkn_e) {
|
||||||
|
tkn_e = strchr(tkn_e+1, '\\');
|
||||||
|
if (tkn_e) {
|
||||||
|
strcat(mountdata, ",prefixpath=");
|
||||||
|
strcat(mountdata, tkn_e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/
|
||||||
|
/*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/
|
||||||
|
|
||||||
|
compose_mount_options_out:
|
||||||
|
kfree(srvIP);
|
||||||
|
return mountdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
|
||||||
|
struct dentry *dentry, char *ref_unc)
|
||||||
|
{
|
||||||
|
struct cifs_sb_info *cifs_sb;
|
||||||
|
struct vfsmount *mnt;
|
||||||
|
char *mountdata;
|
||||||
|
char *devname = NULL;
|
||||||
|
|
||||||
|
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
|
||||||
|
mountdata = compose_mount_options(cifs_sb->mountdata,
|
||||||
|
ref_unc, &devname);
|
||||||
|
|
||||||
|
if (IS_ERR(mountdata))
|
||||||
|
return (struct vfsmount *)mountdata;
|
||||||
|
|
||||||
|
mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
|
||||||
|
kfree(mountdata);
|
||||||
|
kfree(devname);
|
||||||
|
return mnt;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
char *full_path = NULL;
|
||||||
|
char *search_path;
|
||||||
|
char *tmp_path;
|
||||||
|
size_t l_max_len;
|
||||||
|
struct cifs_sb_info *cifs_sb;
|
||||||
|
|
||||||
|
if (dentry->d_inode == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
|
||||||
|
|
||||||
|
if (cifs_sb->tcon == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
search_path = build_path_from_dentry(dentry);
|
||||||
|
if (search_path == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
|
||||||
|
/* we should use full path name to correct working with DFS */
|
||||||
|
l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
|
||||||
|
strnlen(search_path, MAX_PATHCONF) + 1;
|
||||||
|
tmp_path = kmalloc(l_max_len, GFP_KERNEL);
|
||||||
|
if (tmp_path == NULL) {
|
||||||
|
kfree(search_path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
|
||||||
|
strcat(tmp_path, search_path);
|
||||||
|
tmp_path[l_max_len-1] = 0;
|
||||||
|
full_path = tmp_path;
|
||||||
|
kfree(search_path);
|
||||||
|
} else {
|
||||||
|
full_path = search_path;
|
||||||
|
}
|
||||||
|
return full_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
|
||||||
|
struct list_head *mntlist)
|
||||||
|
{
|
||||||
|
/* stolen from afs code */
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mntget(newmnt);
|
||||||
|
err = do_add_mount(newmnt, nd, nd->mnt->mnt_flags, mntlist);
|
||||||
|
switch (err) {
|
||||||
|
case 0:
|
||||||
|
dput(nd->dentry);
|
||||||
|
mntput(nd->mnt);
|
||||||
|
nd->mnt = newmnt;
|
||||||
|
nd->dentry = dget(newmnt->mnt_root);
|
||||||
|
break;
|
||||||
|
case -EBUSY:
|
||||||
|
/* someone else made a mount here whilst we were busy */
|
||||||
|
while (d_mountpoint(nd->dentry) &&
|
||||||
|
follow_down(&nd->mnt, &nd->dentry))
|
||||||
|
;
|
||||||
|
err = 0;
|
||||||
|
default:
|
||||||
|
mntput(newmnt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump_referral(const struct dfs_info3_param *ref)
|
||||||
|
{
|
||||||
|
cFYI(1, ("DFS: ref path: %s", ref->path_name));
|
||||||
|
cFYI(1, ("DFS: node path: %s", ref->node_name));
|
||||||
|
cFYI(1, ("DFS: fl: %hd, srv_type: %hd", ref->flags, ref->server_type));
|
||||||
|
cFYI(1, ("DFS: ref_flags: %hd, path_consumed: %hd", ref->ref_flag,
|
||||||
|
ref->PathConsumed));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void*
|
||||||
|
cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
||||||
|
{
|
||||||
|
struct dfs_info3_param *referrals = NULL;
|
||||||
|
unsigned int num_referrals = 0;
|
||||||
|
struct cifs_sb_info *cifs_sb;
|
||||||
|
struct cifsSesInfo *ses;
|
||||||
|
char *full_path = NULL;
|
||||||
|
int xid, i;
|
||||||
|
int rc = 0;
|
||||||
|
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
|
cFYI(1, ("in %s", __FUNCTION__));
|
||||||
|
BUG_ON(IS_ROOT(dentry));
|
||||||
|
|
||||||
|
xid = GetXid();
|
||||||
|
|
||||||
|
dput(nd->dentry);
|
||||||
|
nd->dentry = dget(dentry);
|
||||||
|
|
||||||
|
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
|
||||||
|
ses = cifs_sb->tcon->ses;
|
||||||
|
|
||||||
|
if (!ses) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_path = build_full_dfs_path_from_dentry(dentry);
|
||||||
|
if (full_path == NULL) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
|
||||||
|
&num_referrals, &referrals,
|
||||||
|
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
|
||||||
|
for (i = 0; i < num_referrals; i++) {
|
||||||
|
dump_referral(referrals+i);
|
||||||
|
/* connect to a storage node */
|
||||||
|
if (referrals[i].flags & DFSREF_STORAGE_SERVER) {
|
||||||
|
int len;
|
||||||
|
len = strlen(referrals[i].node_name);
|
||||||
|
if (len < 2) {
|
||||||
|
cERROR(1, ("%s: Net Address path too short: %s",
|
||||||
|
__FUNCTION__, referrals[i].node_name));
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
mnt = cifs_dfs_do_refmount(nd->mnt, nd->dentry,
|
||||||
|
referrals[i].node_name);
|
||||||
|
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
|
||||||
|
__FUNCTION__,
|
||||||
|
referrals[i].node_name, mnt));
|
||||||
|
|
||||||
|
/* complete mount procedure if we accured submount */
|
||||||
|
if (!IS_ERR(mnt))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we need it cause for() above could exit without valid submount */
|
||||||
|
rc = PTR_ERR(mnt);
|
||||||
|
if (IS_ERR(mnt))
|
||||||
|
goto out_err;
|
||||||
|
|
||||||
|
nd->mnt->mnt_flags |= MNT_SHRINKABLE;
|
||||||
|
rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);
|
||||||
|
|
||||||
|
out:
|
||||||
|
FreeXid(xid);
|
||||||
|
free_dfs_info_array(referrals, num_referrals);
|
||||||
|
kfree(full_path);
|
||||||
|
cFYI(1, ("leaving %s" , __FUNCTION__));
|
||||||
|
return ERR_PTR(rc);
|
||||||
|
out_err:
|
||||||
|
path_release(nd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct inode_operations cifs_dfs_referral_inode_operations = {
|
||||||
|
.follow_link = cifs_dfs_follow_mountpoint,
|
||||||
|
};
|
||||||
|
|
|
@ -43,6 +43,9 @@ struct cifs_sb_info {
|
||||||
mode_t mnt_dir_mode;
|
mode_t mnt_dir_mode;
|
||||||
int mnt_cifs_flags;
|
int mnt_cifs_flags;
|
||||||
int prepathlen;
|
int prepathlen;
|
||||||
char *prepath;
|
char *prepath; /* relative path under the share to mount to */
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
char *mountdata; /* mount options received at mount time */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
#endif /* _CIFS_FS_SB_H */
|
#endif /* _CIFS_FS_SB_H */
|
||||||
|
|
|
@ -122,11 +122,13 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||||
cFYI(1, ("key description = %s", description));
|
cFYI(1, ("key description = %s", description));
|
||||||
spnego_key = request_key(&cifs_spnego_key_type, description, "");
|
spnego_key = request_key(&cifs_spnego_key_type, description, "");
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
if (cifsFYI && !IS_ERR(spnego_key)) {
|
if (cifsFYI && !IS_ERR(spnego_key)) {
|
||||||
struct cifs_spnego_msg *msg = spnego_key->payload.data;
|
struct cifs_spnego_msg *msg = spnego_key->payload.data;
|
||||||
cifs_dump_mem("SPNEGO reply blob:", msg->data,
|
cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024,
|
||||||
msg->secblob_len + msg->sesskey_len);
|
msg->secblob_len + msg->sesskey_len));
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_CIFS_DEBUG2 */
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(description);
|
kfree(description);
|
||||||
|
|
|
@ -129,6 +129,54 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
|
||||||
return (1); /* sids compare/match */
|
return (1); /* sids compare/match */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* copy ntsd, owner sid, and group sid from a security descriptor to another */
|
||||||
|
static void copy_sec_desc(const struct cifs_ntsd *pntsd,
|
||||||
|
struct cifs_ntsd *pnntsd, __u32 sidsoffset)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
||||||
|
struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
|
||||||
|
|
||||||
|
/* copy security descriptor control portion */
|
||||||
|
pnntsd->revision = pntsd->revision;
|
||||||
|
pnntsd->type = pntsd->type;
|
||||||
|
pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
|
||||||
|
pnntsd->sacloffset = 0;
|
||||||
|
pnntsd->osidoffset = cpu_to_le32(sidsoffset);
|
||||||
|
pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
|
||||||
|
|
||||||
|
/* copy owner sid */
|
||||||
|
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||||||
|
le32_to_cpu(pntsd->osidoffset));
|
||||||
|
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
|
||||||
|
|
||||||
|
nowner_sid_ptr->revision = owner_sid_ptr->revision;
|
||||||
|
nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
|
||||||
|
|
||||||
|
/* copy group sid */
|
||||||
|
group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||||||
|
le32_to_cpu(pntsd->gsidoffset));
|
||||||
|
ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
|
||||||
|
sizeof(struct cifs_sid));
|
||||||
|
|
||||||
|
ngroup_sid_ptr->revision = group_sid_ptr->revision;
|
||||||
|
ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
ngroup_sid_ptr->sub_auth[i] =
|
||||||
|
cpu_to_le32(group_sid_ptr->sub_auth[i]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
change posix mode to reflect permissions
|
change posix mode to reflect permissions
|
||||||
pmode is the existing mode (we only want to overwrite part of this
|
pmode is the existing mode (we only want to overwrite part of this
|
||||||
|
@ -220,6 +268,33 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __le16 fill_ace_for_sid(struct cifs_ace *pntace,
|
||||||
|
const struct cifs_sid *psid, __u64 nmode, umode_t bits)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
__u16 size = 0;
|
||||||
|
__u32 access_req = 0;
|
||||||
|
|
||||||
|
pntace->type = ACCESS_ALLOWED;
|
||||||
|
pntace->flags = 0x0;
|
||||||
|
mode_to_access_flags(nmode, bits, &access_req);
|
||||||
|
if (!access_req)
|
||||||
|
access_req = SET_MINIMUM_RIGHTS;
|
||||||
|
pntace->access_req = cpu_to_le32(access_req);
|
||||||
|
|
||||||
|
pntace->sid.revision = psid->revision;
|
||||||
|
pntace->sid.num_subauth = psid->num_subauth;
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
pntace->sid.authority[i] = psid->authority[i];
|
||||||
|
for (i = 0; i < psid->num_subauth; i++)
|
||||||
|
pntace->sid.sub_auth[i] = psid->sub_auth[i];
|
||||||
|
|
||||||
|
size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
|
||||||
|
pntace->size = cpu_to_le16(size);
|
||||||
|
|
||||||
|
return (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_DEBUG2
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
|
static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
|
||||||
|
@ -243,7 +318,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
|
||||||
int i;
|
int i;
|
||||||
cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
|
cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
|
||||||
pace->sid.revision, pace->sid.num_subauth, pace->type,
|
pace->sid.revision, pace->sid.num_subauth, pace->type,
|
||||||
pace->flags, pace->size));
|
pace->flags, le16_to_cpu(pace->size)));
|
||||||
for (i = 0; i < num_subauth; ++i) {
|
for (i = 0; i < num_subauth; ++i) {
|
||||||
cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
|
cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
|
||||||
le32_to_cpu(pace->sid.sub_auth[i])));
|
le32_to_cpu(pace->sid.sub_auth[i])));
|
||||||
|
@ -346,6 +421,28 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
|
||||||
|
struct cifs_sid *pgrpsid, __u64 nmode)
|
||||||
|
{
|
||||||
|
__le16 size = 0;
|
||||||
|
struct cifs_acl *pnndacl;
|
||||||
|
|
||||||
|
pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
|
||||||
|
|
||||||
|
size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
|
||||||
|
pownersid, nmode, S_IRWXU);
|
||||||
|
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
|
||||||
|
pgrpsid, nmode, S_IRWXG);
|
||||||
|
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
|
||||||
|
&sid_everyone, nmode, S_IRWXO);
|
||||||
|
|
||||||
|
pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
|
||||||
|
pndacl->num_aces = 3;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
|
||||||
{
|
{
|
||||||
/* BB need to add parm so we can store the SID BB */
|
/* BB need to add parm so we can store the SID BB */
|
||||||
|
@ -432,6 +529,46 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert permission bits from mode to equivalent CIFS ACL */
|
||||||
|
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
||||||
|
int acl_len, struct inode *inode, __u64 nmode)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
__u32 dacloffset;
|
||||||
|
__u32 ndacloffset;
|
||||||
|
__u32 sidsoffset;
|
||||||
|
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
||||||
|
struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
|
||||||
|
struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
|
||||||
|
|
||||||
|
if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
|
||||||
|
return (-EIO);
|
||||||
|
|
||||||
|
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||||||
|
le32_to_cpu(pntsd->osidoffset));
|
||||||
|
group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
|
||||||
|
le32_to_cpu(pntsd->gsidoffset));
|
||||||
|
|
||||||
|
dacloffset = le32_to_cpu(pntsd->dacloffset);
|
||||||
|
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
|
||||||
|
|
||||||
|
ndacloffset = sizeof(struct cifs_ntsd);
|
||||||
|
ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
|
||||||
|
ndacl_ptr->revision = dacl_ptr->revision;
|
||||||
|
ndacl_ptr->size = 0;
|
||||||
|
ndacl_ptr->num_aces = 0;
|
||||||
|
|
||||||
|
rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
|
||||||
|
|
||||||
|
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
||||||
|
|
||||||
|
/* copy security descriptor control portion and owner and group sid */
|
||||||
|
copy_sec_desc(pntsd, pnntsd, sidsoffset);
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Retrieve an ACL from the server */
|
/* Retrieve an ACL from the server */
|
||||||
static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
|
static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
|
||||||
const char *path)
|
const char *path)
|
||||||
|
@ -487,6 +624,64 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
|
||||||
return pntsd;
|
return pntsd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set an ACL on the server */
|
||||||
|
static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||||
|
struct inode *inode, const char *path)
|
||||||
|
{
|
||||||
|
struct cifsFileInfo *open_file;
|
||||||
|
int unlock_file = FALSE;
|
||||||
|
int xid;
|
||||||
|
int rc = -EIO;
|
||||||
|
__u16 fid;
|
||||||
|
struct super_block *sb;
|
||||||
|
struct cifs_sb_info *cifs_sb;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
|
cFYI(1, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!inode)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
sb = inode->i_sb;
|
||||||
|
if (sb == NULL)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
cifs_sb = CIFS_SB(sb);
|
||||||
|
xid = GetXid();
|
||||||
|
|
||||||
|
open_file = find_readable_file(CIFS_I(inode));
|
||||||
|
if (open_file) {
|
||||||
|
unlock_file = TRUE;
|
||||||
|
fid = open_file->netfid;
|
||||||
|
} else {
|
||||||
|
int oplock = FALSE;
|
||||||
|
/* open file */
|
||||||
|
rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
|
||||||
|
WRITE_DAC, 0, &fid, &oplock, NULL,
|
||||||
|
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||||
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
if (rc != 0) {
|
||||||
|
cERROR(1, ("Unable to open file to set ACL"));
|
||||||
|
FreeXid(xid);
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
|
||||||
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
|
cFYI(1, ("SetCIFSACL rc = %d", rc));
|
||||||
|
#endif
|
||||||
|
if (unlock_file == TRUE)
|
||||||
|
atomic_dec(&open_file->wrtPending);
|
||||||
|
else
|
||||||
|
CIFSSMBClose(xid, cifs_sb->tcon, fid);
|
||||||
|
|
||||||
|
FreeXid(xid);
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
|
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
|
||||||
void acl_to_uid_mode(struct inode *inode, const char *path)
|
void acl_to_uid_mode(struct inode *inode, const char *path)
|
||||||
{
|
{
|
||||||
|
@ -510,24 +705,53 @@ void acl_to_uid_mode(struct inode *inode, const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert mode bits to an ACL so we can update the ACL on the server */
|
/* Convert mode bits to an ACL so we can update the ACL on the server */
|
||||||
int mode_to_acl(struct inode *inode, const char *path)
|
int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
__u32 acllen = 0;
|
__u32 acllen = 0;
|
||||||
struct cifs_ntsd *pntsd = NULL;
|
struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
|
||||||
|
struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
cFYI(1, ("set ACL from mode for %s", path));
|
cFYI(1, ("set ACL from mode for %s", path));
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Get the security descriptor */
|
/* Get the security descriptor */
|
||||||
pntsd = get_cifs_acl(&acllen, inode, path);
|
pntsd = get_cifs_acl(&acllen, inode, path);
|
||||||
|
|
||||||
/* Add/Modify the three ACEs for owner, group, everyone
|
/* Add three ACEs for owner, group, everyone getting rid of
|
||||||
while retaining the other ACEs */
|
other ACEs as chmod disables ACEs and set the security descriptor */
|
||||||
|
|
||||||
/* Set the security descriptor */
|
|
||||||
|
|
||||||
|
if (pntsd) {
|
||||||
|
/* allocate memory for the smb header,
|
||||||
|
set security descriptor request security descriptor
|
||||||
|
parameters, and secuirty descriptor itself */
|
||||||
|
|
||||||
|
pnntsd = kmalloc(acllen, GFP_KERNEL);
|
||||||
|
if (!pnntsd) {
|
||||||
|
cERROR(1, ("Unable to allocate security descriptor"));
|
||||||
kfree(pntsd);
|
kfree(pntsd);
|
||||||
return rc;
|
return (-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = build_sec_desc(pntsd, pnntsd, acllen, inode, nmode);
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
|
cFYI(1, ("build_sec_desc rc: %d", rc));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
/* Set the security descriptor */
|
||||||
|
rc = set_cifs_acl(pnntsd, acllen, inode, path);
|
||||||
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
|
cFYI(1, ("set_cifs_acl rc: %d", rc));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(pnntsd);
|
||||||
|
kfree(pntsd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rc);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "cifs_fs_sb.h"
|
#include "cifs_fs_sb.h"
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/key-type.h>
|
#include <linux/key-type.h>
|
||||||
|
#include "dns_resolve.h"
|
||||||
#include "cifs_spnego.h"
|
#include "cifs_spnego.h"
|
||||||
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
|
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
|
||||||
|
|
||||||
|
@ -96,6 +97,9 @@ cifs_read_super(struct super_block *sb, void *data,
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
int len;
|
||||||
|
#endif
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/* BB should we make this contingent on mount parm? */
|
/* BB should we make this contingent on mount parm? */
|
||||||
|
@ -105,6 +109,25 @@ cifs_read_super(struct super_block *sb, void *data,
|
||||||
if (cifs_sb == NULL)
|
if (cifs_sb == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
/* copy mount params to sb for use in submounts */
|
||||||
|
/* BB: should we move this after the mount so we
|
||||||
|
* do not have to do the copy on failed mounts?
|
||||||
|
* BB: May be it is better to do simple copy before
|
||||||
|
* complex operation (mount), and in case of fail
|
||||||
|
* just exit instead of doing mount and attempting
|
||||||
|
* undo it if this copy fails?*/
|
||||||
|
len = strlen(data);
|
||||||
|
cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
|
||||||
|
if (cifs_sb->mountdata == NULL) {
|
||||||
|
kfree(sb->s_fs_info);
|
||||||
|
sb->s_fs_info = NULL;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
strncpy(cifs_sb->mountdata, data, len + 1);
|
||||||
|
cifs_sb->mountdata[len] = '\0';
|
||||||
|
#endif
|
||||||
|
|
||||||
rc = cifs_mount(sb, cifs_sb, data, devname);
|
rc = cifs_mount(sb, cifs_sb, data, devname);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -154,6 +177,12 @@ out_no_root:
|
||||||
|
|
||||||
out_mount_failed:
|
out_mount_failed:
|
||||||
if (cifs_sb) {
|
if (cifs_sb) {
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
if (cifs_sb->mountdata) {
|
||||||
|
kfree(cifs_sb->mountdata);
|
||||||
|
cifs_sb->mountdata = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (cifs_sb->local_nls)
|
if (cifs_sb->local_nls)
|
||||||
unload_nls(cifs_sb->local_nls);
|
unload_nls(cifs_sb->local_nls);
|
||||||
kfree(cifs_sb);
|
kfree(cifs_sb);
|
||||||
|
@ -177,6 +206,13 @@ cifs_put_super(struct super_block *sb)
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cERROR(1, ("cifs_umount failed with return code %d", rc));
|
cERROR(1, ("cifs_umount failed with return code %d", rc));
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
if (cifs_sb->mountdata) {
|
||||||
|
kfree(cifs_sb->mountdata);
|
||||||
|
cifs_sb->mountdata = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
unload_nls(cifs_sb->local_nls);
|
unload_nls(cifs_sb->local_nls);
|
||||||
kfree(cifs_sb);
|
kfree(cifs_sb);
|
||||||
return;
|
return;
|
||||||
|
@ -435,6 +471,10 @@ static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct cifsTconInfo *tcon;
|
struct cifsTconInfo *tcon;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
dfs_shrink_umount_helper(vfsmnt);
|
||||||
|
#endif /* CONFIG CIFS_DFS_UPCALL */
|
||||||
|
|
||||||
if (!(flags & MNT_FORCE))
|
if (!(flags & MNT_FORCE))
|
||||||
return;
|
return;
|
||||||
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
|
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
|
||||||
|
@ -552,7 +592,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
|
||||||
return remote_llseek(file, offset, origin);
|
return remote_llseek(file, offset, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct file_system_type cifs_fs_type = {
|
struct file_system_type cifs_fs_type = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "cifs",
|
.name = "cifs",
|
||||||
.get_sb = cifs_get_sb,
|
.get_sb = cifs_get_sb,
|
||||||
|
@ -1014,12 +1054,17 @@ init_cifs(void)
|
||||||
rc = register_key_type(&cifs_spnego_key_type);
|
rc = register_key_type(&cifs_spnego_key_type);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_unregister_filesystem;
|
goto out_unregister_filesystem;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
rc = register_key_type(&key_type_dns_resolver);
|
||||||
|
if (rc)
|
||||||
|
goto out_unregister_key_type;
|
||||||
#endif
|
#endif
|
||||||
oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
|
oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
|
||||||
if (IS_ERR(oplockThread)) {
|
if (IS_ERR(oplockThread)) {
|
||||||
rc = PTR_ERR(oplockThread);
|
rc = PTR_ERR(oplockThread);
|
||||||
cERROR(1, ("error %d create oplock thread", rc));
|
cERROR(1, ("error %d create oplock thread", rc));
|
||||||
goto out_unregister_key_type;
|
goto out_unregister_dfs_key_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
|
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
|
||||||
|
@ -1033,7 +1078,11 @@ init_cifs(void)
|
||||||
|
|
||||||
out_stop_oplock_thread:
|
out_stop_oplock_thread:
|
||||||
kthread_stop(oplockThread);
|
kthread_stop(oplockThread);
|
||||||
|
out_unregister_dfs_key_type:
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
unregister_key_type(&key_type_dns_resolver);
|
||||||
out_unregister_key_type:
|
out_unregister_key_type:
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
unregister_key_type(&cifs_spnego_key_type);
|
unregister_key_type(&cifs_spnego_key_type);
|
||||||
out_unregister_filesystem:
|
out_unregister_filesystem:
|
||||||
|
@ -1059,6 +1108,9 @@ exit_cifs(void)
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
cifs_proc_clean();
|
cifs_proc_clean();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
unregister_key_type(&key_type_dns_resolver);
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
unregister_key_type(&cifs_spnego_key_type);
|
unregister_key_type(&cifs_spnego_key_type);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern struct file_system_type cifs_fs_type;
|
||||||
extern const struct address_space_operations cifs_addr_ops;
|
extern const struct address_space_operations cifs_addr_ops;
|
||||||
extern const struct address_space_operations cifs_addr_ops_smallbuf;
|
extern const struct address_space_operations cifs_addr_ops_smallbuf;
|
||||||
|
|
||||||
|
@ -60,6 +61,10 @@ extern int cifs_setattr(struct dentry *, struct iattr *);
|
||||||
|
|
||||||
extern const struct inode_operations cifs_file_inode_ops;
|
extern const struct inode_operations cifs_file_inode_ops;
|
||||||
extern const struct inode_operations cifs_symlink_inode_ops;
|
extern const struct inode_operations cifs_symlink_inode_ops;
|
||||||
|
extern struct list_head cifs_dfs_automount_list;
|
||||||
|
extern struct inode_operations cifs_dfs_referral_inode_operations;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* fs/cifs/cifsglob.h
|
* fs/cifs/cifsglob.h
|
||||||
*
|
*
|
||||||
* Copyright (C) International Business Machines Corp., 2002,2007
|
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||||
* 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)
|
||||||
*
|
*
|
||||||
|
@ -69,14 +69,6 @@
|
||||||
#define XATTR_DOS_ATTRIB "user.DOSATTRIB"
|
#define XATTR_DOS_ATTRIB "user.DOSATTRIB"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* This information is kept on every Server we know about.
|
|
||||||
*
|
|
||||||
* Some things to note:
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CIFS vfs client Status information (based on what we know.)
|
* CIFS vfs client Status information (based on what we know.)
|
||||||
*/
|
*/
|
||||||
|
@ -460,6 +452,37 @@ struct dir_notify_req {
|
||||||
struct file *pfile;
|
struct file *pfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dfs_info3_param {
|
||||||
|
int flags; /* DFSREF_REFERRAL_SERVER, DFSREF_STORAGE_SERVER*/
|
||||||
|
int PathConsumed;
|
||||||
|
int server_type;
|
||||||
|
int ref_flag;
|
||||||
|
char *path_name;
|
||||||
|
char *node_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void free_dfs_info_param(struct dfs_info3_param *param)
|
||||||
|
{
|
||||||
|
if (param) {
|
||||||
|
kfree(param->path_name);
|
||||||
|
kfree(param->node_name);
|
||||||
|
kfree(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void free_dfs_info_array(struct dfs_info3_param *param,
|
||||||
|
int number_of_items)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if ((number_of_items == 0) || (param == NULL))
|
||||||
|
return;
|
||||||
|
for (i = 0; i < number_of_items; i++) {
|
||||||
|
kfree(param[i].path_name);
|
||||||
|
kfree(param[i].node_name);
|
||||||
|
}
|
||||||
|
kfree(param);
|
||||||
|
}
|
||||||
|
|
||||||
#define MID_FREE 0
|
#define MID_FREE 0
|
||||||
#define MID_REQUEST_ALLOCATED 1
|
#define MID_REQUEST_ALLOCATED 1
|
||||||
#define MID_REQUEST_SUBMITTED 2
|
#define MID_REQUEST_SUBMITTED 2
|
||||||
|
|
|
@ -237,6 +237,9 @@
|
||||||
| DELETE | READ_CONTROL | WRITE_DAC \
|
| DELETE | READ_CONTROL | WRITE_DAC \
|
||||||
| WRITE_OWNER | SYNCHRONIZE)
|
| WRITE_OWNER | SYNCHRONIZE)
|
||||||
|
|
||||||
|
#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \
|
||||||
|
| READ_CONTROL | SYNCHRONIZE)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invalid readdir handle
|
* Invalid readdir handle
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* fs/cifs/cifsproto.h
|
* fs/cifs/cifsproto.h
|
||||||
*
|
*
|
||||||
* Copyright (c) International Business Machines Corp., 2002,2007
|
* Copyright (c) International Business Machines Corp., 2002,2008
|
||||||
* 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
|
||||||
|
@ -97,11 +97,14 @@ extern int cifs_get_inode_info_unix(struct inode **pinode,
|
||||||
const unsigned char *search_path,
|
const unsigned char *search_path,
|
||||||
struct super_block *sb, int xid);
|
struct super_block *sb, int xid);
|
||||||
extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
|
extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
|
||||||
extern int mode_to_acl(struct inode *inode, const char *path);
|
extern int mode_to_acl(struct inode *inode, const char *path, __u64);
|
||||||
|
|
||||||
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
||||||
const char *);
|
const char *);
|
||||||
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
|
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
|
||||||
|
#endif
|
||||||
void cifs_proc_init(void);
|
void cifs_proc_init(void);
|
||||||
void cifs_proc_clean(void);
|
void cifs_proc_clean(void);
|
||||||
|
|
||||||
|
@ -153,7 +156,7 @@ extern int 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,
|
struct dfs_info3_param **preferrals,
|
||||||
int remap);
|
int remap);
|
||||||
extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
|
extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
|
||||||
struct super_block *sb, struct smb_vol *vol);
|
struct super_block *sb, struct smb_vol *vol);
|
||||||
|
@ -342,6 +345,8 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
|
||||||
const struct nls_table *nls_codepage, int remap_special_chars);
|
const struct nls_table *nls_codepage, int remap_special_chars);
|
||||||
extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
|
extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
|
||||||
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
|
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
|
||||||
|
extern int CIFSSMBSetCIFSACL(const int, struct cifsTconInfo *, __u16,
|
||||||
|
struct cifs_ntsd *, __u32);
|
||||||
extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
|
extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
|
||||||
const unsigned char *searchName,
|
const unsigned char *searchName,
|
||||||
char *acl_inf, const int buflen, const int acl_type,
|
char *acl_inf, const int buflen, const int acl_type,
|
||||||
|
|
|
@ -3156,6 +3156,71 @@ qsec_out:
|
||||||
/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
|
/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
|
||||||
|
struct cifs_ntsd *pntsd, __u32 acllen)
|
||||||
|
{
|
||||||
|
__u16 byte_count, param_count, data_count, param_offset, data_offset;
|
||||||
|
int rc = 0;
|
||||||
|
int bytes_returned = 0;
|
||||||
|
SET_SEC_DESC_REQ *pSMB = NULL;
|
||||||
|
NTRANSACT_RSP *pSMBr = NULL;
|
||||||
|
|
||||||
|
setCifsAclRetry:
|
||||||
|
rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
|
||||||
|
(void **) &pSMBr);
|
||||||
|
if (rc)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
pSMB->MaxSetupCount = 0;
|
||||||
|
pSMB->Reserved = 0;
|
||||||
|
|
||||||
|
param_count = 8;
|
||||||
|
param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
|
||||||
|
data_count = acllen;
|
||||||
|
data_offset = param_offset + param_count;
|
||||||
|
byte_count = 3 /* pad */ + param_count;
|
||||||
|
|
||||||
|
pSMB->DataCount = cpu_to_le32(data_count);
|
||||||
|
pSMB->TotalDataCount = pSMB->DataCount;
|
||||||
|
pSMB->MaxParameterCount = cpu_to_le32(4);
|
||||||
|
pSMB->MaxDataCount = cpu_to_le32(16384);
|
||||||
|
pSMB->ParameterCount = cpu_to_le32(param_count);
|
||||||
|
pSMB->ParameterOffset = cpu_to_le32(param_offset);
|
||||||
|
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||||
|
pSMB->DataOffset = cpu_to_le32(data_offset);
|
||||||
|
pSMB->SetupCount = 0;
|
||||||
|
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
|
||||||
|
pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
|
||||||
|
|
||||||
|
pSMB->Fid = fid; /* file handle always le */
|
||||||
|
pSMB->Reserved2 = 0;
|
||||||
|
pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
|
||||||
|
|
||||||
|
if (pntsd && acllen) {
|
||||||
|
memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
|
||||||
|
(char *) pntsd,
|
||||||
|
acllen);
|
||||||
|
pSMB->hdr.smb_buf_length += (byte_count + data_count);
|
||||||
|
|
||||||
|
} else
|
||||||
|
pSMB->hdr.smb_buf_length += byte_count;
|
||||||
|
|
||||||
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||||
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||||
|
|
||||||
|
cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
|
||||||
|
if (rc)
|
||||||
|
cFYI(1, ("Set CIFS ACL returned %d", rc));
|
||||||
|
cifs_buf_release(pSMB);
|
||||||
|
|
||||||
|
if (rc == -EAGAIN)
|
||||||
|
goto setCifsAclRetry;
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||||
|
|
||||||
/* Legacy Query Path Information call for lookup to old servers such
|
/* Legacy Query Path Information call for lookup to old servers such
|
||||||
|
@ -5499,7 +5564,7 @@ SetEARetry:
|
||||||
else
|
else
|
||||||
name_len = strnlen(ea_name, 255);
|
name_len = strnlen(ea_name, 255);
|
||||||
|
|
||||||
count = sizeof(*parm_data) + ea_value_len + name_len + 1;
|
count = sizeof(*parm_data) + ea_value_len + name_len;
|
||||||
pSMB->MaxParameterCount = cpu_to_le16(2);
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
||||||
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
|
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
|
||||||
pSMB->MaxSetupCount = 0;
|
pSMB->MaxSetupCount = 0;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* fs/cifs/connect.c
|
* fs/cifs/connect.c
|
||||||
*
|
*
|
||||||
* Copyright (C) International Business Machines Corp., 2002,2007
|
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||||
* 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
|
||||||
|
@ -1410,7 +1410,7 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
|
||||||
const char *old_path, const struct nls_table *nls_codepage,
|
const char *old_path, const struct nls_table *nls_codepage,
|
||||||
int remap)
|
int remap)
|
||||||
{
|
{
|
||||||
unsigned char *referrals = NULL;
|
struct dfs_info3_param *referrals = NULL;
|
||||||
unsigned int num_referrals;
|
unsigned int num_referrals;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
@ -1429,12 +1429,14 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
|
||||||
int
|
int
|
||||||
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
|
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
|
||||||
const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
|
const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
|
||||||
unsigned char **preferrals, int remap)
|
struct dfs_info3_param **preferrals, int remap)
|
||||||
{
|
{
|
||||||
char *temp_unc;
|
char *temp_unc;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
unsigned char *targetUNCs;
|
||||||
|
|
||||||
*pnum_referrals = 0;
|
*pnum_referrals = 0;
|
||||||
|
*preferrals = NULL;
|
||||||
|
|
||||||
if (pSesInfo->ipc_tid == 0) {
|
if (pSesInfo->ipc_tid == 0) {
|
||||||
temp_unc = kmalloc(2 /* for slashes */ +
|
temp_unc = kmalloc(2 /* for slashes */ +
|
||||||
|
@ -1454,8 +1456,10 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
|
||||||
kfree(temp_unc);
|
kfree(temp_unc);
|
||||||
}
|
}
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
|
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
|
||||||
pnum_referrals, nls_codepage, remap);
|
pnum_referrals, nls_codepage, remap);
|
||||||
|
/* BB map targetUNCs to dfs_info3 structures, here or
|
||||||
|
in CIFSGetDFSRefer BB */
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1964,7 +1968,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||||
|
|
||||||
if (existingCifsSes) {
|
if (existingCifsSes) {
|
||||||
pSesInfo = existingCifsSes;
|
pSesInfo = existingCifsSes;
|
||||||
cFYI(1, ("Existing smb sess found"));
|
cFYI(1, ("Existing smb sess found (status=%d)",
|
||||||
|
pSesInfo->status));
|
||||||
|
down(&pSesInfo->sesSem);
|
||||||
|
if (pSesInfo->status == CifsNeedReconnect) {
|
||||||
|
cFYI(1, ("Session needs reconnect"));
|
||||||
|
rc = cifs_setup_session(xid, pSesInfo,
|
||||||
|
cifs_sb->local_nls);
|
||||||
|
}
|
||||||
|
up(&pSesInfo->sesSem);
|
||||||
} else if (!rc) {
|
} else if (!rc) {
|
||||||
cFYI(1, ("Existing smb sess not found"));
|
cFYI(1, ("Existing smb sess not found"));
|
||||||
pSesInfo = sesInfoAlloc();
|
pSesInfo = sesInfoAlloc();
|
||||||
|
@ -3514,7 +3526,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
|
||||||
sesInfoFree(ses);
|
sesInfoFree(ses);
|
||||||
|
|
||||||
FreeXid(xid);
|
FreeXid(xid);
|
||||||
return rc; /* BB check if we should always return zero here */
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
||||||
|
|
|
@ -517,12 +517,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||||
d_add(direntry, NULL);
|
d_add(direntry, NULL);
|
||||||
/* if it was once a directory (but how can we tell?) we could do
|
/* if it was once a directory (but how can we tell?) we could do
|
||||||
shrink_dcache_parent(direntry); */
|
shrink_dcache_parent(direntry); */
|
||||||
} else {
|
} else if (rc != -EACCES) {
|
||||||
cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
|
cERROR(1, ("Unexpected lookup error %d", rc));
|
||||||
rc, full_path));
|
/* We special case check for Access Denied - since that
|
||||||
/* BB special case check for Access Denied - watch security
|
is a common return code */
|
||||||
exposure of returning dir info implicitly via different rc
|
|
||||||
if file exists or not but no access BB */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(full_path);
|
kfree(full_path);
|
||||||
|
|
124
fs/cifs/dns_resolve.c
Normal file
124
fs/cifs/dns_resolve.c
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* fs/cifs/dns_resolve.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Igor Mammedov
|
||||||
|
* Author(s): Igor Mammedov (niallain@gmail.com)
|
||||||
|
* Steve French (sfrench@us.ibm.com)
|
||||||
|
*
|
||||||
|
* Contains the CIFS DFS upcall routines used for hostname to
|
||||||
|
* IP address translation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <keys/user-type.h>
|
||||||
|
#include "dns_resolve.h"
|
||||||
|
#include "cifsglob.h"
|
||||||
|
#include "cifsproto.h"
|
||||||
|
#include "cifs_debug.h"
|
||||||
|
|
||||||
|
static int dns_resolver_instantiate(struct key *key, const void *data,
|
||||||
|
size_t datalen)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
char *ip;
|
||||||
|
|
||||||
|
ip = kmalloc(datalen+1, GFP_KERNEL);
|
||||||
|
if (!ip)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memcpy(ip, data, datalen);
|
||||||
|
ip[datalen] = '\0';
|
||||||
|
|
||||||
|
rcu_assign_pointer(key->payload.data, ip);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct key_type key_type_dns_resolver = {
|
||||||
|
.name = "dns_resolver",
|
||||||
|
.def_datalen = sizeof(struct in_addr),
|
||||||
|
.describe = user_describe,
|
||||||
|
.instantiate = dns_resolver_instantiate,
|
||||||
|
.match = user_match,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Resolves server name to ip address.
|
||||||
|
* input:
|
||||||
|
* unc - server UNC
|
||||||
|
* output:
|
||||||
|
* *ip_addr - pointer to server ip, caller responcible for freeing it.
|
||||||
|
* return 0 on success
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
|
||||||
|
{
|
||||||
|
int rc = -EAGAIN;
|
||||||
|
struct key *rkey;
|
||||||
|
char *name;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (!ip_addr || !unc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* search for server name delimiter */
|
||||||
|
len = strlen(unc);
|
||||||
|
if (len < 3) {
|
||||||
|
cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
len -= 2;
|
||||||
|
name = memchr(unc+2, '\\', len);
|
||||||
|
if (!name) {
|
||||||
|
cFYI(1, ("%s: probably server name is whole unc: %s",
|
||||||
|
__FUNCTION__, unc));
|
||||||
|
} else {
|
||||||
|
len = (name - unc) - 2/* leading // */;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = kmalloc(len+1, GFP_KERNEL);
|
||||||
|
if (!name) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
memcpy(name, unc+2, len);
|
||||||
|
name[len] = 0;
|
||||||
|
|
||||||
|
rkey = request_key(&key_type_dns_resolver, name, "");
|
||||||
|
if (!IS_ERR(rkey)) {
|
||||||
|
len = strlen(rkey->payload.data);
|
||||||
|
*ip_addr = kmalloc(len+1, GFP_KERNEL);
|
||||||
|
if (*ip_addr) {
|
||||||
|
memcpy(*ip_addr, rkey->payload.data, len);
|
||||||
|
(*ip_addr)[len] = '\0';
|
||||||
|
cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__,
|
||||||
|
rkey->description,
|
||||||
|
*ip_addr
|
||||||
|
));
|
||||||
|
rc = 0;
|
||||||
|
} else {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
}
|
||||||
|
key_put(rkey);
|
||||||
|
} else {
|
||||||
|
cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(name);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
32
fs/cifs/dns_resolve.h
Normal file
32
fs/cifs/dns_resolve.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* fs/cifs/dns_resolve.h -- DNS Resolver upcall management for CIFS DFS
|
||||||
|
* Handles host name to IP address resolution
|
||||||
|
*
|
||||||
|
* Copyright (c) International Business Machines Corp., 2008
|
||||||
|
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DNS_RESOLVE_H
|
||||||
|
#define _DNS_RESOLVE_H
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#include <linux/key-type.h>
|
||||||
|
extern struct key_type key_type_dns_resolver;
|
||||||
|
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
|
||||||
|
#endif /* KERNEL */
|
||||||
|
|
||||||
|
#endif /* _DNS_RESOLVE_H */
|
|
@ -1179,12 +1179,10 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
||||||
atomic_dec(&open_file->wrtPending);
|
atomic_dec(&open_file->wrtPending);
|
||||||
/* Does mm or vfs already set times? */
|
/* Does mm or vfs already set times? */
|
||||||
inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
|
inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
|
||||||
if ((bytes_written > 0) && (offset)) {
|
if ((bytes_written > 0) && (offset))
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} else if (bytes_written < 0) {
|
else if (bytes_written < 0)
|
||||||
if (rc != -EBADF)
|
|
||||||
rc = bytes_written;
|
rc = bytes_written;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
cFYI(1, ("No writeable filehandles for inode"));
|
cFYI(1, ("No writeable filehandles for inode"));
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
|
|
@ -54,9 +54,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
||||||
MAX_TREE_SIZE + 1) +
|
MAX_TREE_SIZE + 1) +
|
||||||
strnlen(search_path, MAX_PATHCONF) + 1,
|
strnlen(search_path, MAX_PATHCONF) + 1,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (tmp_path == NULL) {
|
if (tmp_path == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
/* have to skip first of the double backslash of
|
/* have to skip first of the double backslash of
|
||||||
UNC name */
|
UNC name */
|
||||||
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
|
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
|
||||||
|
@ -511,7 +511,8 @@ int cifs_get_inode_info(struct inode **pinode,
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
|
if (is_size_safe_to_change(cifsInfo,
|
||||||
|
le64_to_cpu(pfindData->EndOfFile))) {
|
||||||
/* can not safely shrink the file size here if the
|
/* can not safely shrink the file size here if the
|
||||||
client is writing to it due to potential races */
|
client is writing to it due to potential races */
|
||||||
i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
|
i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
|
||||||
|
@ -1607,7 +1608,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
else if (attrs->ia_valid & ATTR_MODE) {
|
else if (attrs->ia_valid & ATTR_MODE) {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if ((mode & S_IWUGO) == 0) /* not writeable */ {
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
|
||||||
|
rc = mode_to_acl(direntry->d_inode, full_path, mode);
|
||||||
|
else if ((mode & S_IWUGO) == 0) {
|
||||||
|
#else
|
||||||
|
if ((mode & S_IWUGO) == 0) {
|
||||||
|
#endif
|
||||||
|
/* not writeable */
|
||||||
if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
|
if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
|
||||||
set_dosattr = TRUE;
|
set_dosattr = TRUE;
|
||||||
time_buf.Attributes =
|
time_buf.Attributes =
|
||||||
|
@ -1626,10 +1634,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||||
if (time_buf.Attributes == 0)
|
if (time_buf.Attributes == 0)
|
||||||
time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
|
time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
|
||||||
}
|
}
|
||||||
/* BB to be implemented -
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
via Windows security descriptors or streams */
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
|
||||||
/* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
|
mode_to_acl(direntry->d_inode, full_path, mode);
|
||||||
cifs_sb->local_nls); */
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attrs->ia_valid & ATTR_ATIME) {
|
if (attrs->ia_valid & ATTR_ATIME) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* fs/cifs/link.c
|
* fs/cifs/link.c
|
||||||
*
|
*
|
||||||
* Copyright (C) International Business Machines Corp., 2002,2003
|
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||||
* 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
|
||||||
|
@ -236,8 +236,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
||||||
char *full_path = NULL;
|
char *full_path = NULL;
|
||||||
char *tmp_path = NULL;
|
char *tmp_path = NULL;
|
||||||
char *tmpbuffer;
|
char *tmpbuffer;
|
||||||
unsigned char *referrals = NULL;
|
|
||||||
unsigned int num_referrals = 0;
|
|
||||||
int len;
|
int len;
|
||||||
__u16 fid;
|
__u16 fid;
|
||||||
|
|
||||||
|
@ -297,8 +295,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
||||||
cFYI(1, ("Error closing junction point "
|
cFYI(1, ("Error closing junction point "
|
||||||
"(open for ioctl)"));
|
"(open for ioctl)"));
|
||||||
}
|
}
|
||||||
|
/* BB unwind this long, nested function, or remove BB */
|
||||||
if (rc == -EIO) {
|
if (rc == -EIO) {
|
||||||
/* Query if DFS Junction */
|
/* Query if DFS Junction */
|
||||||
|
unsigned int num_referrals = 0;
|
||||||
|
struct dfs_info3_param *refs = NULL;
|
||||||
tmp_path =
|
tmp_path =
|
||||||
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
|
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
@ -310,7 +311,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
||||||
rc = get_dfs_path(xid, pTcon->ses,
|
rc = get_dfs_path(xid, pTcon->ses,
|
||||||
tmp_path,
|
tmp_path,
|
||||||
cifs_sb->local_nls,
|
cifs_sb->local_nls,
|
||||||
&num_referrals, &referrals,
|
&num_referrals, &refs,
|
||||||
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 ",
|
cFYI(1, ("Get DFS for %s rc = %d ",
|
||||||
|
@ -320,14 +321,13 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
||||||
else {
|
else {
|
||||||
cFYI(1, ("num referral: %d",
|
cFYI(1, ("num referral: %d",
|
||||||
num_referrals));
|
num_referrals));
|
||||||
if (referrals) {
|
if (refs && refs->path_name) {
|
||||||
cFYI(1,("referral string: %s", referrals));
|
|
||||||
strncpy(tmpbuffer,
|
strncpy(tmpbuffer,
|
||||||
referrals,
|
refs->path_name,
|
||||||
len-1);
|
len-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kfree(referrals);
|
kfree(refs);
|
||||||
kfree(tmp_path);
|
kfree(tmp_path);
|
||||||
}
|
}
|
||||||
/* BB add code like else decode referrals
|
/* BB add code like else decode referrals
|
||||||
|
|
|
@ -528,9 +528,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||||
rc = -EOVERFLOW;
|
rc = -EOVERFLOW;
|
||||||
goto ssetup_exit;
|
goto ssetup_exit;
|
||||||
}
|
}
|
||||||
|
if (first_time) {
|
||||||
ses->server->mac_signing_key.len = msg->sesskey_len;
|
ses->server->mac_signing_key.len = msg->sesskey_len;
|
||||||
memcpy(ses->server->mac_signing_key.data.krb5, msg->data,
|
memcpy(ses->server->mac_signing_key.data.krb5,
|
||||||
msg->sesskey_len);
|
msg->data, msg->sesskey_len);
|
||||||
|
}
|
||||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||||
capabilities |= CAP_EXTENDED_SECURITY;
|
capabilities |= CAP_EXTENDED_SECURITY;
|
||||||
pSMB->req.Capabilities = cpu_to_le32(capabilities);
|
pSMB->req.Capabilities = cpu_to_le32(capabilities);
|
||||||
|
@ -540,7 +542,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||||
|
|
||||||
if (ses->capabilities & CAP_UNICODE) {
|
if (ses->capabilities & CAP_UNICODE) {
|
||||||
/* unicode strings must be word aligned */
|
/* unicode strings must be word aligned */
|
||||||
if (iov[0].iov_len % 2) {
|
if ((iov[0].iov_len + iov[1].iov_len) % 2) {
|
||||||
*bcc_ptr = 0;
|
*bcc_ptr = 0;
|
||||||
bcc_ptr++;
|
bcc_ptr++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue