mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +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] 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
37
fs/Kconfig
37
fs/Kconfig
@ -1899,13 +1899,15 @@ config CIFS
|
||||
file servers such as Windows 2000 (including Windows 2003, NT 4
|
||||
and Windows XP) as well by Samba (which provides excellent CIFS
|
||||
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
|
||||
network file system client for mounting to CIFS compliant servers,
|
||||
including support for dfs (hierarchical name space), secure per-user
|
||||
session establishment, safe distributed caching (oplock), optional
|
||||
packet signing, Unicode and other internationalization improvements.
|
||||
The cifs module provides an advanced network file system
|
||||
client for mounting to CIFS compliant servers. It includes
|
||||
support for DFS (hierarchical name space), secure per-user
|
||||
session establishment via Kerberos or NTLM or NTLMv2,
|
||||
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.
|
||||
|
||||
config CIFS_STATS
|
||||
@ -1937,7 +1939,8 @@ config CIFS_WEAK_PW_HASH
|
||||
(since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
|
||||
security mechanisms. These hash the password more securely
|
||||
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
|
||||
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
|
||||
have a need to access old SMB servers (and are on a private
|
||||
network) you probably want to say N. Even if this support
|
||||
is enabled in the kernel build, they will not be used
|
||||
automatically. At runtime LANMAN mounts are disabled but
|
||||
is enabled in the kernel build, LANMAN authentication will not be
|
||||
used automatically. At runtime LANMAN mounts are disabled but
|
||||
can be set to required (or optional) either in
|
||||
/proc/fs/cifs (see fs/cifs/README for more detail) or via an
|
||||
option on the mount command. This support is disabled by
|
||||
@ -2012,12 +2015,22 @@ config CIFS_UPCALL
|
||||
depends on CIFS_EXPERIMENTAL
|
||||
depends on KEYS
|
||||
help
|
||||
Enables an upcall mechanism for CIFS which will be used to contact
|
||||
userspace helper utilities to provide SPNEGO packaged Kerberos
|
||||
tickets which are needed to mount to certain secure servers
|
||||
Enables an upcall mechanism for CIFS which accesses
|
||||
userspace helper utilities to provide SPNEGO packaged (RFC 4178)
|
||||
Kerberos tickets which are needed to mount to certain secure servers
|
||||
(for which more secure Kerberos authentication is required). If
|
||||
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
|
||||
tristate "NCP file system support (to mount NetWare volumes)"
|
||||
depends on IPX!=n || INET
|
||||
|
@ -3,7 +3,10 @@ Version 1.52
|
||||
Fix oops on second mount to server when null auth is used.
|
||||
Enable experimental Kerberos support. Return writebehind errors on flush
|
||||
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
|
||||
------------
|
||||
|
@ -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
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -248,7 +249,7 @@ A partial list of the supported mount options follows:
|
||||
the CIFS session.
|
||||
password The user password. If the mount helper is
|
||||
installed, the user will be prompted for password
|
||||
if it is not supplied.
|
||||
if not supplied.
|
||||
ip The ip address of the target server
|
||||
unc The target server Universal Network Name (export) to
|
||||
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
|
||||
the client. Note that the mount.cifs helper must be
|
||||
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).
|
||||
file_mode If CIFS Unix extensions are not supported by the server
|
||||
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
|
||||
supports them. (default)
|
||||
noacl Do not allow setfacl and getfacl calls on this mount
|
||||
user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended
|
||||
attributes) to the server (default) e.g. via setfattr
|
||||
and getfattr utilities.
|
||||
user_xattr Allow getting and setting user xattrs (those attributes whose
|
||||
name begins with "user." or "os2.") as OS/2 EAs (extended
|
||||
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
|
||||
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).
|
||||
nocase Request case insensitive path name matching (case
|
||||
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
|
||||
negotiate posix path name support which allows certain
|
||||
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
|
||||
lanman (if configured in kernel config) use older
|
||||
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
|
||||
including:
|
||||
@ -535,8 +541,8 @@ SecurityFlags Flags which control security negotiation and
|
||||
must use NTLM 0x02002
|
||||
may use NTLMv2 0x00004
|
||||
must use NTLMv2 0x04004
|
||||
may use Kerberos security (not implemented yet) 0x00008
|
||||
must use Kerberos (not implemented yet) 0x08008
|
||||
may use Kerberos security 0x00008
|
||||
must use Kerberos 0x08008
|
||||
may use lanman (weak) password hash 0x00010
|
||||
must use lanman password hash 0x10010
|
||||
may use plaintext passwords 0x00020
|
||||
@ -626,6 +632,6 @@ returned success.
|
||||
|
||||
Also note that "cat /proc/fs/cifs/DebugData" will display information about
|
||||
the active sessions and the shares that are mounted.
|
||||
Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled
|
||||
but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
|
||||
LANMAN support do not require this helpr.
|
||||
Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is
|
||||
on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
|
||||
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
|
||||
==================================
|
||||
@ -16,16 +16,14 @@ SecurityDescriptors
|
||||
c) Better pam/winbind integration (e.g. to handle uid mapping
|
||||
better)
|
||||
|
||||
d) Verify that Kerberos signing works
|
||||
|
||||
e) Cleanup now unneeded SessSetup code in
|
||||
d) Cleanup now unneeded SessSetup code in
|
||||
fs/cifs/connect.c and add back in NTLMSSP code if any servers
|
||||
need it
|
||||
|
||||
f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup
|
||||
used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
|
||||
and raw NTLMSSP already. This is important when enabling
|
||||
extended security and mounting to Windows 2003 Servers
|
||||
e) ms-dfs and ms-dfs host name resolution cleanup
|
||||
|
||||
f) fix NTLMv2 signing when two mounts with different users to same
|
||||
server.
|
||||
|
||||
g) Directory entry caching relies on a 1 second timer, rather than
|
||||
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;
|
||||
int mnt_cifs_flags;
|
||||
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 */
|
||||
|
@ -122,11 +122,13 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||
cFYI(1, ("key description = %s", description));
|
||||
spnego_key = request_key(&cifs_spnego_key_type, description, "");
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
if (cifsFYI && !IS_ERR(spnego_key)) {
|
||||
struct cifs_spnego_msg *msg = spnego_key->payload.data;
|
||||
cifs_dump_mem("SPNEGO reply blob:", msg->data,
|
||||
msg->secblob_len + msg->sesskey_len);
|
||||
cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024,
|
||||
msg->secblob_len + msg->sesskey_len));
|
||||
}
|
||||
#endif /* CONFIG_CIFS_DEBUG2 */
|
||||
|
||||
out:
|
||||
kfree(description);
|
||||
|
@ -129,6 +129,54 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
|
||||
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) {
|
||||
cFYI(1, ("ACE sub_auth[%d]: 0x%x", 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)
|
||||
{
|
||||
/* 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 */
|
||||
static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
|
||||
const char *path)
|
||||
@ -487,6 +624,64 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
|
||||
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 */
|
||||
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 */
|
||||
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;
|
||||
__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));
|
||||
#endif
|
||||
|
||||
/* Get the security descriptor */
|
||||
pntsd = get_cifs_acl(&acllen, inode, path);
|
||||
|
||||
/* Add/Modify the three ACEs for owner, group, everyone
|
||||
while retaining the other ACEs */
|
||||
/* Add three ACEs for owner, group, everyone getting rid of
|
||||
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);
|
||||
return (-ENOMEM);
|
||||
}
|
||||
|
||||
kfree(pntsd);
|
||||
return rc;
|
||||
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 */
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "cifs_fs_sb.h"
|
||||
#include <linux/mm.h>
|
||||
#include <linux/key-type.h>
|
||||
#include "dns_resolve.h"
|
||||
#include "cifs_spnego.h"
|
||||
#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 cifs_sb_info *cifs_sb;
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
int len;
|
||||
#endif
|
||||
int rc = 0;
|
||||
|
||||
/* 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)
|
||||
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);
|
||||
|
||||
if (rc) {
|
||||
@ -154,6 +177,12 @@ out_no_root:
|
||||
|
||||
out_mount_failed:
|
||||
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)
|
||||
unload_nls(cifs_sb->local_nls);
|
||||
kfree(cifs_sb);
|
||||
@ -177,6 +206,13 @@ cifs_put_super(struct super_block *sb)
|
||||
if (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);
|
||||
kfree(cifs_sb);
|
||||
return;
|
||||
@ -435,6 +471,10 @@ static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *tcon;
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
dfs_shrink_umount_helper(vfsmnt);
|
||||
#endif /* CONFIG CIFS_DFS_UPCALL */
|
||||
|
||||
if (!(flags & MNT_FORCE))
|
||||
return;
|
||||
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);
|
||||
}
|
||||
|
||||
static struct file_system_type cifs_fs_type = {
|
||||
struct file_system_type cifs_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cifs",
|
||||
.get_sb = cifs_get_sb,
|
||||
@ -1014,12 +1054,17 @@ init_cifs(void)
|
||||
rc = register_key_type(&cifs_spnego_key_type);
|
||||
if (rc)
|
||||
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
|
||||
oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
|
||||
if (IS_ERR(oplockThread)) {
|
||||
rc = PTR_ERR(oplockThread);
|
||||
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");
|
||||
@ -1033,7 +1078,11 @@ init_cifs(void)
|
||||
|
||||
out_stop_oplock_thread:
|
||||
kthread_stop(oplockThread);
|
||||
out_unregister_dfs_key_type:
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
unregister_key_type(&key_type_dns_resolver);
|
||||
out_unregister_key_type:
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
unregister_key_type(&cifs_spnego_key_type);
|
||||
out_unregister_filesystem:
|
||||
@ -1059,6 +1108,9 @@ exit_cifs(void)
|
||||
#ifdef CONFIG_PROC_FS
|
||||
cifs_proc_clean();
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
unregister_key_type(&key_type_dns_resolver);
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
unregister_key_type(&cifs_spnego_key_type);
|
||||
#endif
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define TRUE 1
|
||||
#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_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_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 */
|
||||
extern const struct file_operations cifs_file_ops;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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)
|
||||
* Jeremy Allison (jra@samba.org)
|
||||
*
|
||||
@ -69,14 +69,6 @@
|
||||
#define XATTR_DOS_ATTRIB "user.DOSATTRIB"
|
||||
#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.)
|
||||
*/
|
||||
@ -460,6 +452,37 @@ struct dir_notify_req {
|
||||
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_REQUEST_ALLOCATED 1
|
||||
#define MID_REQUEST_SUBMITTED 2
|
||||
|
@ -237,6 +237,9 @@
|
||||
| DELETE | READ_CONTROL | WRITE_DAC \
|
||||
| WRITE_OWNER | SYNCHRONIZE)
|
||||
|
||||
#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \
|
||||
| READ_CONTROL | SYNCHRONIZE)
|
||||
|
||||
|
||||
/*
|
||||
* Invalid readdir handle
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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)
|
||||
*
|
||||
* 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,
|
||||
struct super_block *sb, int xid);
|
||||
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 *,
|
||||
const char *);
|
||||
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_clean(void);
|
||||
|
||||
@ -153,7 +156,7 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
|
||||
const char *old_path,
|
||||
const struct nls_table *nls_codepage,
|
||||
unsigned int *pnum_referrals,
|
||||
unsigned char **preferrals,
|
||||
struct dfs_info3_param **preferrals,
|
||||
int remap);
|
||||
extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
|
||||
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);
|
||||
extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
|
||||
__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,
|
||||
const unsigned char *searchName,
|
||||
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 */
|
||||
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 */
|
||||
|
||||
/* Legacy Query Path Information call for lookup to old servers such
|
||||
@ -5499,7 +5564,7 @@ SetEARetry:
|
||||
else
|
||||
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->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
|
||||
pSMB->MaxSetupCount = 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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)
|
||||
*
|
||||
* 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,
|
||||
int remap)
|
||||
{
|
||||
unsigned char *referrals = NULL;
|
||||
struct dfs_info3_param *referrals = NULL;
|
||||
unsigned int num_referrals;
|
||||
int rc = 0;
|
||||
|
||||
@ -1429,12 +1429,14 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
|
||||
int
|
||||
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
|
||||
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;
|
||||
int rc = 0;
|
||||
unsigned char *targetUNCs;
|
||||
|
||||
*pnum_referrals = 0;
|
||||
*preferrals = NULL;
|
||||
|
||||
if (pSesInfo->ipc_tid == 0) {
|
||||
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);
|
||||
}
|
||||
if (rc == 0)
|
||||
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
|
||||
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
|
||||
pnum_referrals, nls_codepage, remap);
|
||||
/* BB map targetUNCs to dfs_info3 structures, here or
|
||||
in CIFSGetDFSRefer BB */
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -1964,7 +1968,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
|
||||
if (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) {
|
||||
cFYI(1, ("Existing smb sess not found"));
|
||||
pSesInfo = sesInfoAlloc();
|
||||
@ -3514,7 +3526,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
|
||||
sesInfoFree(ses);
|
||||
|
||||
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,
|
||||
|
@ -517,12 +517,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
d_add(direntry, NULL);
|
||||
/* if it was once a directory (but how can we tell?) we could do
|
||||
shrink_dcache_parent(direntry); */
|
||||
} else {
|
||||
cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
|
||||
rc, full_path));
|
||||
/* BB special case check for Access Denied - watch security
|
||||
exposure of returning dir info implicitly via different rc
|
||||
if file exists or not but no access BB */
|
||||
} else if (rc != -EACCES) {
|
||||
cERROR(1, ("Unexpected lookup error %d", rc));
|
||||
/* We special case check for Access Denied - since that
|
||||
is a common return code */
|
||||
}
|
||||
|
||||
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);
|
||||
/* Does mm or vfs already set times? */
|
||||
inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
|
||||
if ((bytes_written > 0) && (offset)) {
|
||||
if ((bytes_written > 0) && (offset))
|
||||
rc = 0;
|
||||
} else if (bytes_written < 0) {
|
||||
if (rc != -EBADF)
|
||||
rc = bytes_written;
|
||||
}
|
||||
else if (bytes_written < 0)
|
||||
rc = bytes_written;
|
||||
} else {
|
||||
cFYI(1, ("No writeable filehandles for inode"));
|
||||
rc = -EIO;
|
||||
|
@ -54,9 +54,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
MAX_TREE_SIZE + 1) +
|
||||
strnlen(search_path, MAX_PATHCONF) + 1,
|
||||
GFP_KERNEL);
|
||||
if (tmp_path == NULL) {
|
||||
if (tmp_path == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* have to skip first of the double backslash of
|
||||
UNC name */
|
||||
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);
|
||||
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
|
||||
client is writing to it due to potential races */
|
||||
i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
|
||||
@ -931,7 +932,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||
le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
|
||||
u32 oplock = 0;
|
||||
FILE_UNIX_BASIC_INFO * pInfo =
|
||||
FILE_UNIX_BASIC_INFO *pInfo =
|
||||
kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
|
||||
if (pInfo == NULL) {
|
||||
rc = -ENOMEM;
|
||||
@ -1607,7 +1608,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
else if (attrs->ia_valid & ATTR_MODE) {
|
||||
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) {
|
||||
set_dosattr = TRUE;
|
||||
time_buf.Attributes =
|
||||
@ -1626,10 +1634,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
if (time_buf.Attributes == 0)
|
||||
time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
|
||||
}
|
||||
/* BB to be implemented -
|
||||
via Windows security descriptors or streams */
|
||||
/* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
|
||||
cifs_sb->local_nls); */
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
|
||||
mode_to_acl(direntry->d_inode, full_path, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (attrs->ia_valid & ATTR_ATIME) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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)
|
||||
*
|
||||
* 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 *tmp_path = NULL;
|
||||
char *tmpbuffer;
|
||||
unsigned char *referrals = NULL;
|
||||
unsigned int num_referrals = 0;
|
||||
int len;
|
||||
__u16 fid;
|
||||
|
||||
@ -297,8 +295,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
||||
cFYI(1, ("Error closing junction point "
|
||||
"(open for ioctl)"));
|
||||
}
|
||||
/* BB unwind this long, nested function, or remove BB */
|
||||
if (rc == -EIO) {
|
||||
/* Query if DFS Junction */
|
||||
unsigned int num_referrals = 0;
|
||||
struct dfs_info3_param *refs = NULL;
|
||||
tmp_path =
|
||||
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
|
||||
GFP_KERNEL);
|
||||
@ -310,7 +311,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
||||
rc = get_dfs_path(xid, pTcon->ses,
|
||||
tmp_path,
|
||||
cifs_sb->local_nls,
|
||||
&num_referrals, &referrals,
|
||||
&num_referrals, &refs,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
cFYI(1, ("Get DFS for %s rc = %d ",
|
||||
@ -320,14 +321,13 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
|
||||
else {
|
||||
cFYI(1, ("num referral: %d",
|
||||
num_referrals));
|
||||
if (referrals) {
|
||||
cFYI(1,("referral string: %s", referrals));
|
||||
if (refs && refs->path_name) {
|
||||
strncpy(tmpbuffer,
|
||||
referrals,
|
||||
refs->path_name,
|
||||
len-1);
|
||||
}
|
||||
}
|
||||
kfree(referrals);
|
||||
kfree(refs);
|
||||
kfree(tmp_path);
|
||||
}
|
||||
/* BB add code like else decode referrals
|
||||
|
@ -528,9 +528,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
rc = -EOVERFLOW;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
ses->server->mac_signing_key.len = msg->sesskey_len;
|
||||
memcpy(ses->server->mac_signing_key.data.krb5, msg->data,
|
||||
msg->sesskey_len);
|
||||
if (first_time) {
|
||||
ses->server->mac_signing_key.len = msg->sesskey_len;
|
||||
memcpy(ses->server->mac_signing_key.data.krb5,
|
||||
msg->data, msg->sesskey_len);
|
||||
}
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
capabilities |= CAP_EXTENDED_SECURITY;
|
||||
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) {
|
||||
/* 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++;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user