Commit ef3f2de2 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 1c7c2cde 366781c1
......@@ -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.
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.
support for OS/2 and Windows ME and similar servers is provided as
well.
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.
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)
......
/*
* 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 @@ cifs_read_super(struct super_block *sb, void *data,
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;
......
/*
* 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
......
/*
* 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 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
/* 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 @@ CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
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;
......
/*
* 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);
......
/*
* 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;
}
/*
* 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) {
......
/*
* 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++;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment