aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-27 02:01:20 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-27 02:01:20 -0500
commitef3f2de2b5496f721b12f21a157e19eac816394b (patch)
treee2aa39d46714e7956ed12b85cd9490ef327abaff /fs
parent1c7c2cdec3a6b2873439096983794a550d7ff65b (diff)
parent366781c19635d861f43ff5e03388a3873ec912d9 (diff)
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
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig39
-rw-r--r--fs/cifs/CHANGES5
-rw-r--r--fs/cifs/Makefile2
-rw-r--r--fs/cifs/README28
-rw-r--r--fs/cifs/TODO14
-rw-r--r--fs/cifs/cifs_dfs_ref.c377
-rw-r--r--fs/cifs/cifs_fs_sb.h5
-rw-r--r--fs/cifs/cifs_spnego.c6
-rw-r--r--fs/cifs/cifsacl.c240
-rw-r--r--fs/cifs/cifsfs.c56
-rw-r--r--fs/cifs/cifsfs.h5
-rw-r--r--fs/cifs/cifsglob.h41
-rw-r--r--fs/cifs/cifspdu.h3
-rw-r--r--fs/cifs/cifsproto.h11
-rw-r--r--fs/cifs/cifssmb.c67
-rw-r--r--fs/cifs/connect.c24
-rw-r--r--fs/cifs/dir.c10
-rw-r--r--fs/cifs/dns_resolve.c124
-rw-r--r--fs/cifs/dns_resolve.h32
-rw-r--r--fs/cifs/file.c8
-rw-r--r--fs/cifs/inode.c26
-rw-r--r--fs/cifs/link.c16
-rw-r--r--fs/cifs/sess.c10
23 files changed, 1052 insertions, 97 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index b6df18f1f677..9656139d2e99 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1899,13 +1899,15 @@ config CIFS
1899 file servers such as Windows 2000 (including Windows 2003, NT 4 1899 file servers such as Windows 2000 (including Windows 2003, NT 4
1900 and Windows XP) as well by Samba (which provides excellent CIFS 1900 and Windows XP) as well by Samba (which provides excellent CIFS
1901 server support for Linux and many other operating systems). Limited 1901 server support for Linux and many other operating systems). Limited
1902 support for OS/2 and Windows ME and similar servers is provided as well. 1902 support for OS/2 and Windows ME and similar servers is provided as
1903 1903 well.
1904 The intent of the cifs module is to provide an advanced 1904
1905 network file system client for mounting to CIFS compliant servers, 1905 The cifs module provides an advanced network file system
1906 including support for dfs (hierarchical name space), secure per-user 1906 client for mounting to CIFS compliant servers. It includes
1907 session establishment, safe distributed caching (oplock), optional 1907 support for DFS (hierarchical name space), secure per-user
1908 packet signing, Unicode and other internationalization improvements. 1908 session establishment via Kerberos or NTLM or NTLMv2,
1909 safe distributed caching (oplock), optional packet
1910 signing, Unicode and other internationalization improvements.
1909 If you need to mount to Samba or Windows from this machine, say Y. 1911 If you need to mount to Samba or Windows from this machine, say Y.
1910 1912
1911config CIFS_STATS 1913config CIFS_STATS
@@ -1937,7 +1939,8 @@ config CIFS_WEAK_PW_HASH
1937 (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos) 1939 (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
1938 security mechanisms. These hash the password more securely 1940 security mechanisms. These hash the password more securely
1939 than the mechanisms used in the older LANMAN version of the 1941 than the mechanisms used in the older LANMAN version of the
1940 SMB protocol needed to establish sessions with old SMB servers. 1942 SMB protocol but LANMAN based authentication is needed to
1943 establish sessions with some old SMB servers.
1941 1944
1942 Enabling this option allows the cifs module to mount to older 1945 Enabling this option allows the cifs module to mount to older
1943 LANMAN based servers such as OS/2 and Windows 95, but such 1946 LANMAN based servers such as OS/2 and Windows 95, but such
@@ -1945,8 +1948,8 @@ config CIFS_WEAK_PW_HASH
1945 security mechanisms if you are on a public network. Unless you 1948 security mechanisms if you are on a public network. Unless you
1946 have a need to access old SMB servers (and are on a private 1949 have a need to access old SMB servers (and are on a private
1947 network) you probably want to say N. Even if this support 1950 network) you probably want to say N. Even if this support
1948 is enabled in the kernel build, they will not be used 1951 is enabled in the kernel build, LANMAN authentication will not be
1949 automatically. At runtime LANMAN mounts are disabled but 1952 used automatically. At runtime LANMAN mounts are disabled but
1950 can be set to required (or optional) either in 1953 can be set to required (or optional) either in
1951 /proc/fs/cifs (see fs/cifs/README for more detail) or via an 1954 /proc/fs/cifs (see fs/cifs/README for more detail) or via an
1952 option on the mount command. This support is disabled by 1955 option on the mount command. This support is disabled by
@@ -2012,12 +2015,22 @@ config CIFS_UPCALL
2012 depends on CIFS_EXPERIMENTAL 2015 depends on CIFS_EXPERIMENTAL
2013 depends on KEYS 2016 depends on KEYS
2014 help 2017 help
2015 Enables an upcall mechanism for CIFS which will be used to contact 2018 Enables an upcall mechanism for CIFS which accesses
2016 userspace helper utilities to provide SPNEGO packaged Kerberos 2019 userspace helper utilities to provide SPNEGO packaged (RFC 4178)
2017 tickets which are needed to mount to certain secure servers 2020 Kerberos tickets which are needed to mount to certain secure servers
2018 (for which more secure Kerberos authentication is required). If 2021 (for which more secure Kerberos authentication is required). If
2019 unsure, say N. 2022 unsure, say N.
2020 2023
2024config CIFS_DFS_UPCALL
2025 bool "DFS feature support (EXPERIMENTAL)"
2026 depends on CIFS_EXPERIMENTAL
2027 depends on KEYS
2028 help
2029 Enables an upcall mechanism for CIFS which contacts userspace
2030 helper utilities to provide server name resolution (host names to
2031 IP addresses) which is needed for implicit mounts of DFS junction
2032 points. If unsure, say N.
2033
2021config NCP_FS 2034config NCP_FS
2022 tristate "NCP file system support (to mount NetWare volumes)" 2035 tristate "NCP file system support (to mount NetWare volumes)"
2023 depends on IPX!=n || INET 2036 depends on IPX!=n || INET
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index a609599287aa..edd248367b36 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -3,7 +3,10 @@ Version 1.52
3Fix oops on second mount to server when null auth is used. 3Fix oops on second mount to server when null auth is used.
4Enable experimental Kerberos support. Return writebehind errors on flush 4Enable experimental Kerberos support. Return writebehind errors on flush
5and sync so that events like out of disk space get reported properly on 5and sync so that events like out of disk space get reported properly on
6cached files. 6cached files. Fix setxattr failure to certain Samba versions. Fix mount
7of second share to disconnected server session (autoreconnect on this).
8Add ability to modify cifs acls for handling chmod (when mounted with
9cifsacl flag).
7 10
8Version 1.51 11Version 1.51
9------------ 12------------
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 45e42fb97c19..6ba43fb346fb 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -9,3 +9,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
9 readdir.o ioctl.o sess.o export.o cifsacl.o 9 readdir.o ioctl.o sess.o export.o cifsacl.o
10 10
11cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o 11cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
12
13cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
diff --git a/fs/cifs/README b/fs/cifs/README
index bf11329ac784..c623e2f9c5db 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -56,7 +56,8 @@ the CIFS VFS web site) copy it to the same directory in which mount.smbfs and
56similar files reside (usually /sbin). Although the helper software is not 56similar files reside (usually /sbin). Although the helper software is not
57required, mount.cifs is recommended. Eventually the Samba 3.0 utility program 57required, mount.cifs is recommended. Eventually the Samba 3.0 utility program
58"net" may also be helpful since it may someday provide easier mount syntax for 58"net" may also be helpful since it may someday provide easier mount syntax for
59users who are used to Windows e.g. net use <mount point> <UNC name or cifs URL> 59users who are used to Windows e.g.
60 net use <mount point> <UNC name or cifs URL>
60Note that running the Winbind pam/nss module (logon service) on all of your 61Note that running the Winbind pam/nss module (logon service) on all of your
61Linux clients is useful in mapping Uids and Gids consistently across the 62Linux clients is useful in mapping Uids and Gids consistently across the
62domain to the proper network user. The mount.cifs mount helper can be 63domain 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:
248 the CIFS session. 249 the CIFS session.
249 password The user password. If the mount helper is 250 password The user password. If the mount helper is
250 installed, the user will be prompted for password 251 installed, the user will be prompted for password
251 if it is not supplied. 252 if not supplied.
252 ip The ip address of the target server 253 ip The ip address of the target server
253 unc The target server Universal Network Name (export) to 254 unc The target server Universal Network Name (export) to
254 mount. 255 mount.
@@ -283,7 +284,7 @@ A partial list of the supported mount options follows:
283 can be enabled by specifying file_mode and dir_mode on 284 can be enabled by specifying file_mode and dir_mode on
284 the client. Note that the mount.cifs helper must be 285 the client. Note that the mount.cifs helper must be
285 at version 1.10 or higher to support specifying the uid 286 at version 1.10 or higher to support specifying the uid
286 (or gid) in non-numberic form. 287 (or gid) in non-numeric form.
287 gid Set the default gid for inodes (similar to above). 288 gid Set the default gid for inodes (similar to above).
288 file_mode If CIFS Unix extensions are not supported by the server 289 file_mode If CIFS Unix extensions are not supported by the server
289 this overrides the default mode for file inodes. 290 this overrides the default mode for file inodes.
@@ -417,9 +418,10 @@ A partial list of the supported mount options follows:
417 acl Allow setfacl and getfacl to manage posix ACLs if server 418 acl Allow setfacl and getfacl to manage posix ACLs if server
418 supports them. (default) 419 supports them. (default)
419 noacl Do not allow setfacl and getfacl calls on this mount 420 noacl Do not allow setfacl and getfacl calls on this mount
420 user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended 421 user_xattr Allow getting and setting user xattrs (those attributes whose
421 attributes) to the server (default) e.g. via setfattr 422 name begins with "user." or "os2.") as OS/2 EAs (extended
422 and getfattr utilities. 423 attributes) to the server. This allows support of the
424 setfattr and getfattr utilities. (default)
423 nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs 425 nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs
424 mapchars Translate six of the seven reserved characters (not backslash) 426 mapchars Translate six of the seven reserved characters (not backslash)
425 *?<>|: 427 *?<>|:
@@ -434,6 +436,7 @@ A partial list of the supported mount options follows:
434 nomapchars Do not translate any of these seven characters (default). 436 nomapchars Do not translate any of these seven characters (default).
435 nocase Request case insensitive path name matching (case 437 nocase Request case insensitive path name matching (case
436 sensitive is the default if the server suports it). 438 sensitive is the default if the server suports it).
439 (mount option "ignorecase" is identical to "nocase")
437 posixpaths If CIFS Unix extensions are supported, attempt to 440 posixpaths If CIFS Unix extensions are supported, attempt to
438 negotiate posix path name support which allows certain 441 negotiate posix path name support which allows certain
439 characters forbidden in typical CIFS filenames, without 442 characters forbidden in typical CIFS filenames, without
@@ -485,6 +488,9 @@ A partial list of the supported mount options follows:
485 ntlmv2i Use NTLMv2 password hashing with packet signing 488 ntlmv2i Use NTLMv2 password hashing with packet signing
486 lanman (if configured in kernel config) use older 489 lanman (if configured in kernel config) use older
487 lanman hash 490 lanman hash
491hard Retry file operations if server is not responding
492soft Limit retries to unresponsive servers (usually only
493 one retry) before returning an error. (default)
488 494
489The mount.cifs mount helper also accepts a few mount options before -o 495The mount.cifs mount helper also accepts a few mount options before -o
490including: 496including:
@@ -535,8 +541,8 @@ SecurityFlags Flags which control security negotiation and
535 must use NTLM 0x02002 541 must use NTLM 0x02002
536 may use NTLMv2 0x00004 542 may use NTLMv2 0x00004
537 must use NTLMv2 0x04004 543 must use NTLMv2 0x04004
538 may use Kerberos security (not implemented yet) 0x00008 544 may use Kerberos security 0x00008
539 must use Kerberos (not implemented yet) 0x08008 545 must use Kerberos 0x08008
540 may use lanman (weak) password hash 0x00010 546 may use lanman (weak) password hash 0x00010
541 must use lanman password hash 0x10010 547 must use lanman password hash 0x10010
542 may use plaintext passwords 0x00020 548 may use plaintext passwords 0x00020
@@ -626,6 +632,6 @@ returned success.
626 632
627Also note that "cat /proc/fs/cifs/DebugData" will display information about 633Also note that "cat /proc/fs/cifs/DebugData" will display information about
628the active sessions and the shares that are mounted. 634the active sessions and the shares that are mounted.
629Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled 635Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is
630but requires a user space helper (from the Samba project). NTLM and NTLMv2 and 636on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
631LANMAN support do not require this helpr. 637LANMAN support do not require this helper.
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index a8852c200728..92c9feac440f 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
1Version 1.49 April 26, 2007 1Version 1.52 January 3, 2008
2 2
3A Partial List of Missing Features 3A Partial List of Missing Features
4================================== 4==================================
@@ -16,16 +16,14 @@ SecurityDescriptors
16c) Better pam/winbind integration (e.g. to handle uid mapping 16c) Better pam/winbind integration (e.g. to handle uid mapping
17better) 17better)
18 18
19d) Verify that Kerberos signing works 19d) Cleanup now unneeded SessSetup code in
20
21e) Cleanup now unneeded SessSetup code in
22fs/cifs/connect.c and add back in NTLMSSP code if any servers 20fs/cifs/connect.c and add back in NTLMSSP code if any servers
23need it 21need it
24 22
25f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup 23e) ms-dfs and ms-dfs host name resolution cleanup
26used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM 24
27and raw NTLMSSP already. This is important when enabling 25f) fix NTLMv2 signing when two mounts with different users to same
28extended security and mounting to Windows 2003 Servers 26server.
29 27
30g) Directory entry caching relies on a 1 second timer, rather than 28g) Directory entry caching relies on a 1 second timer, rather than
31using FindNotify or equivalent. - (started) 29using FindNotify or equivalent. - (started)
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
new file mode 100644
index 000000000000..413ee2349d1a
--- /dev/null
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -0,0 +1,377 @@
1/*
2 * Contains the CIFS DFS referral mounting routines used for handling
3 * traversal via DFS junction point
4 *
5 * Copyright (c) 2007 Igor Mammedov
6 * Copyright (C) International Business Machines Corp., 2008
7 * Author(s): Igor Mammedov (niallain@gmail.com)
8 * Steve French (sfrench@us.ibm.com)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
15#include <linux/dcache.h>
16#include <linux/mount.h>
17#include <linux/namei.h>
18#include <linux/vfs.h>
19#include <linux/fs.h>
20#include "cifsglob.h"
21#include "cifsproto.h"
22#include "cifsfs.h"
23#include "dns_resolve.h"
24#include "cifs_debug.h"
25
26LIST_HEAD(cifs_dfs_automount_list);
27
28/*
29 * DFS functions
30*/
31
32void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
33{
34 mark_mounts_for_expiry(&cifs_dfs_automount_list);
35 mark_mounts_for_expiry(&cifs_dfs_automount_list);
36 shrink_submounts(vfsmnt, &cifs_dfs_automount_list);
37}
38
39/**
40 * cifs_get_share_name - extracts share name from UNC
41 * @node_name: pointer to UNC string
42 *
43 * Extracts sharename form full UNC.
44 * i.e. strips from UNC trailing path that is not part of share
45 * name and fixup missing '\' in the begining of DFS node refferal
46 * if neccessary.
47 * Returns pointer to share name on success or NULL on error.
48 * Caller is responsible for freeing returned string.
49 */
50static char *cifs_get_share_name(const char *node_name)
51{
52 int len;
53 char *UNC;
54 char *pSep;
55
56 len = strlen(node_name);
57 UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
58 GFP_KERNEL);
59 if (!UNC)
60 return NULL;
61
62 /* get share name and server name */
63 if (node_name[1] != '\\') {
64 UNC[0] = '\\';
65 strncpy(UNC+1, node_name, len);
66 len++;
67 UNC[len] = 0;
68 } else {
69 strncpy(UNC, node_name, len);
70 UNC[len] = 0;
71 }
72
73 /* find server name end */
74 pSep = memchr(UNC+2, '\\', len-2);
75 if (!pSep) {
76 cERROR(1, ("%s: no server name end in node name: %s",
77 __FUNCTION__, node_name));
78 kfree(UNC);
79 return NULL;
80 }
81
82 /* find sharename end */
83 pSep++;
84 pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
85 if (!pSep) {
86 cERROR(1, ("%s:2 cant find share name in node name: %s",
87 __FUNCTION__, node_name));
88 kfree(UNC);
89 return NULL;
90 }
91 /* trim path up to sharename end
92 * * now we have share name in UNC */
93 *pSep = 0;
94
95 return UNC;
96}
97
98
99/**
100 * compose_mount_options - creates mount options for refferral
101 * @sb_mountdata: parent/root DFS mount options (template)
102 * @ref_unc: refferral server UNC
103 * @devname: pointer for saving device name
104 *
105 * creates mount options for submount based on template options sb_mountdata
106 * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
107 *
108 * Returns: pointer to new mount options or ERR_PTR.
109 * Caller is responcible for freeing retunrned value if it is not error.
110 */
111static char *compose_mount_options(const char *sb_mountdata,
112 const char *ref_unc,
113 char **devname)
114{
115 int rc;
116 char *mountdata;
117 int md_len;
118 char *tkn_e;
119 char *srvIP = NULL;
120 char sep = ',';
121 int off, noff;
122
123 if (sb_mountdata == NULL)
124 return ERR_PTR(-EINVAL);
125
126 *devname = cifs_get_share_name(ref_unc);
127 rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
128 if (rc != 0) {
129 cERROR(1, ("%s: Failed to resolve server part of %s to IP",
130 __FUNCTION__, *devname));
131 mountdata = ERR_PTR(rc);
132 goto compose_mount_options_out;
133 }
134 md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3;
135 mountdata = kzalloc(md_len+1, GFP_KERNEL);
136 if (mountdata == NULL) {
137 mountdata = ERR_PTR(-ENOMEM);
138 goto compose_mount_options_out;
139 }
140
141 /* copy all options except of unc,ip,prefixpath */
142 off = 0;
143 if (strncmp(sb_mountdata, "sep=", 4) == 0) {
144 sep = sb_mountdata[4];
145 strncpy(mountdata, sb_mountdata, 5);
146 off += 5;
147 }
148 while ((tkn_e = strchr(sb_mountdata+off, sep))) {
149 noff = (tkn_e - (sb_mountdata+off)) + 1;
150 if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) {
151 off += noff;
152 continue;
153 }
154 if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) {
155 off += noff;
156 continue;
157 }
158 if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) {
159 off += noff;
160 continue;
161 }
162 strncat(mountdata, sb_mountdata+off, noff);
163 off += noff;
164 }
165 strcat(mountdata, sb_mountdata+off);
166 mountdata[md_len] = '\0';
167
168 /* copy new IP and ref share name */
169 strcat(mountdata, ",ip=");
170 strcat(mountdata, srvIP);
171 strcat(mountdata, ",unc=");
172 strcat(mountdata, *devname);
173
174 /* find & copy prefixpath */
175 tkn_e = strchr(ref_unc+2, '\\');
176 if (tkn_e) {
177 tkn_e = strchr(tkn_e+1, '\\');
178 if (tkn_e) {
179 strcat(mountdata, ",prefixpath=");
180 strcat(mountdata, tkn_e);
181 }
182 }
183
184 /*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/
185 /*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/
186
187compose_mount_options_out:
188 kfree(srvIP);
189 return mountdata;
190}
191
192
193static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
194 struct dentry *dentry, char *ref_unc)
195{
196 struct cifs_sb_info *cifs_sb;
197 struct vfsmount *mnt;
198 char *mountdata;
199 char *devname = NULL;
200
201 cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
202 mountdata = compose_mount_options(cifs_sb->mountdata,
203 ref_unc, &devname);
204
205 if (IS_ERR(mountdata))
206 return (struct vfsmount *)mountdata;
207
208 mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
209 kfree(mountdata);
210 kfree(devname);
211 return mnt;
212
213}
214
215static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
216{
217 char *full_path = NULL;
218 char *search_path;
219 char *tmp_path;
220 size_t l_max_len;
221 struct cifs_sb_info *cifs_sb;
222
223 if (dentry->d_inode == NULL)
224 return NULL;
225
226 cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
227
228 if (cifs_sb->tcon == NULL)
229 return NULL;
230
231 search_path = build_path_from_dentry(dentry);
232 if (search_path == NULL)
233 return NULL;
234
235 if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
236 /* we should use full path name to correct working with DFS */
237 l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
238 strnlen(search_path, MAX_PATHCONF) + 1;
239 tmp_path = kmalloc(l_max_len, GFP_KERNEL);
240 if (tmp_path == NULL) {
241 kfree(search_path);
242 return NULL;
243 }
244 strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
245 strcat(tmp_path, search_path);
246 tmp_path[l_max_len-1] = 0;
247 full_path = tmp_path;
248 kfree(search_path);
249 } else {
250 full_path = search_path;
251 }
252 return full_path;
253}
254
255static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
256 struct list_head *mntlist)
257{
258 /* stolen from afs code */
259 int err;
260
261 mntget(newmnt);
262 err = do_add_mount(newmnt, nd, nd->mnt->mnt_flags, mntlist);
263 switch (err) {
264 case 0:
265 dput(nd->dentry);
266 mntput(nd->mnt);
267 nd->mnt = newmnt;
268 nd->dentry = dget(newmnt->mnt_root);
269 break;
270 case -EBUSY:
271 /* someone else made a mount here whilst we were busy */
272 while (d_mountpoint(nd->dentry) &&
273 follow_down(&nd->mnt, &nd->dentry))
274 ;
275 err = 0;
276 default:
277 mntput(newmnt);
278 break;
279 }
280 return err;
281}
282
283static void dump_referral(const struct dfs_info3_param *ref)
284{
285 cFYI(1, ("DFS: ref path: %s", ref->path_name));
286 cFYI(1, ("DFS: node path: %s", ref->node_name));
287 cFYI(1, ("DFS: fl: %hd, srv_type: %hd", ref->flags, ref->server_type));
288 cFYI(1, ("DFS: ref_flags: %hd, path_consumed: %hd", ref->ref_flag,
289 ref->PathConsumed));
290}
291
292
293static void*
294cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
295{
296 struct dfs_info3_param *referrals = NULL;
297 unsigned int num_referrals = 0;
298 struct cifs_sb_info *cifs_sb;
299 struct cifsSesInfo *ses;
300 char *full_path = NULL;
301 int xid, i;
302 int rc = 0;
303 struct vfsmount *mnt = ERR_PTR(-ENOENT);
304
305 cFYI(1, ("in %s", __FUNCTION__));
306 BUG_ON(IS_ROOT(dentry));
307
308 xid = GetXid();
309
310 dput(nd->dentry);
311 nd->dentry = dget(dentry);
312
313 cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
314 ses = cifs_sb->tcon->ses;
315
316 if (!ses) {
317 rc = -EINVAL;
318 goto out_err;
319 }
320
321 full_path = build_full_dfs_path_from_dentry(dentry);
322 if (full_path == NULL) {
323 rc = -ENOMEM;
324 goto out_err;
325 }
326
327 rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
328 &num_referrals, &referrals,
329 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
330
331 for (i = 0; i < num_referrals; i++) {
332 dump_referral(referrals+i);
333 /* connect to a storage node */
334 if (referrals[i].flags & DFSREF_STORAGE_SERVER) {
335 int len;
336 len = strlen(referrals[i].node_name);
337 if (len < 2) {
338 cERROR(1, ("%s: Net Address path too short: %s",
339 __FUNCTION__, referrals[i].node_name));
340 rc = -EINVAL;
341 goto out_err;
342 }
343 mnt = cifs_dfs_do_refmount(nd->mnt, nd->dentry,
344 referrals[i].node_name);
345 cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
346 __FUNCTION__,
347 referrals[i].node_name, mnt));
348
349 /* complete mount procedure if we accured submount */
350 if (!IS_ERR(mnt))
351 break;
352 }
353 }
354
355 /* we need it cause for() above could exit without valid submount */
356 rc = PTR_ERR(mnt);
357 if (IS_ERR(mnt))
358 goto out_err;
359
360 nd->mnt->mnt_flags |= MNT_SHRINKABLE;
361 rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);
362
363out:
364 FreeXid(xid);
365 free_dfs_info_array(referrals, num_referrals);
366 kfree(full_path);
367 cFYI(1, ("leaving %s" , __FUNCTION__));
368 return ERR_PTR(rc);
369out_err:
370 path_release(nd);
371 goto out;
372}
373
374struct inode_operations cifs_dfs_referral_inode_operations = {
375 .follow_link = cifs_dfs_follow_mountpoint,
376};
377
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 34af556cdd8d..8ad2330ba061 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -43,6 +43,9 @@ struct cifs_sb_info {
43 mode_t mnt_dir_mode; 43 mode_t mnt_dir_mode;
44 int mnt_cifs_flags; 44 int mnt_cifs_flags;
45 int prepathlen; 45 int prepathlen;
46 char *prepath; 46 char *prepath; /* relative path under the share to mount to */
47#ifdef CONFIG_CIFS_DFS_UPCALL
48 char *mountdata; /* mount options received at mount time */
49#endif
47}; 50};
48#endif /* _CIFS_FS_SB_H */ 51#endif /* _CIFS_FS_SB_H */
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 1529d2b12e9c..d543accc10dd 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -122,11 +122,13 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
122 cFYI(1, ("key description = %s", description)); 122 cFYI(1, ("key description = %s", description));
123 spnego_key = request_key(&cifs_spnego_key_type, description, ""); 123 spnego_key = request_key(&cifs_spnego_key_type, description, "");
124 124
125#ifdef CONFIG_CIFS_DEBUG2
125 if (cifsFYI && !IS_ERR(spnego_key)) { 126 if (cifsFYI && !IS_ERR(spnego_key)) {
126 struct cifs_spnego_msg *msg = spnego_key->payload.data; 127 struct cifs_spnego_msg *msg = spnego_key->payload.data;
127 cifs_dump_mem("SPNEGO reply blob:", msg->data, 128 cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024,
128 msg->secblob_len + msg->sesskey_len); 129 msg->secblob_len + msg->sesskey_len));
129 } 130 }
131#endif /* CONFIG_CIFS_DEBUG2 */
130 132
131out: 133out:
132 kfree(description); 134 kfree(description);
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index c312adcba4fc..a7035bd18e4e 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -129,6 +129,54 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
129 return (1); /* sids compare/match */ 129 return (1); /* sids compare/match */
130} 130}
131 131
132
133/* copy ntsd, owner sid, and group sid from a security descriptor to another */
134static void copy_sec_desc(const struct cifs_ntsd *pntsd,
135 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
136{
137 int i;
138
139 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
140 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
141
142 /* copy security descriptor control portion */
143 pnntsd->revision = pntsd->revision;
144 pnntsd->type = pntsd->type;
145 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
146 pnntsd->sacloffset = 0;
147 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
148 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
149
150 /* copy owner sid */
151 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
152 le32_to_cpu(pntsd->osidoffset));
153 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
154
155 nowner_sid_ptr->revision = owner_sid_ptr->revision;
156 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
157 for (i = 0; i < 6; i++)
158 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
159 for (i = 0; i < 5; i++)
160 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
161
162 /* copy group sid */
163 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
164 le32_to_cpu(pntsd->gsidoffset));
165 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
166 sizeof(struct cifs_sid));
167
168 ngroup_sid_ptr->revision = group_sid_ptr->revision;
169 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
170 for (i = 0; i < 6; i++)
171 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
172 for (i = 0; i < 5; i++)
173 ngroup_sid_ptr->sub_auth[i] =
174 cpu_to_le32(group_sid_ptr->sub_auth[i]);
175
176 return;
177}
178
179
132/* 180/*
133 change posix mode to reflect permissions 181 change posix mode to reflect permissions
134 pmode is the existing mode (we only want to overwrite part of this 182 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,
220 return; 268 return;
221} 269}
222 270
271static __le16 fill_ace_for_sid(struct cifs_ace *pntace,
272 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
273{
274 int i;
275 __u16 size = 0;
276 __u32 access_req = 0;
277
278 pntace->type = ACCESS_ALLOWED;
279 pntace->flags = 0x0;
280 mode_to_access_flags(nmode, bits, &access_req);
281 if (!access_req)
282 access_req = SET_MINIMUM_RIGHTS;
283 pntace->access_req = cpu_to_le32(access_req);
284
285 pntace->sid.revision = psid->revision;
286 pntace->sid.num_subauth = psid->num_subauth;
287 for (i = 0; i < 6; i++)
288 pntace->sid.authority[i] = psid->authority[i];
289 for (i = 0; i < psid->num_subauth; i++)
290 pntace->sid.sub_auth[i] = psid->sub_auth[i];
291
292 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
293 pntace->size = cpu_to_le16(size);
294
295 return (size);
296}
297
223 298
224#ifdef CONFIG_CIFS_DEBUG2 299#ifdef CONFIG_CIFS_DEBUG2
225static void dump_ace(struct cifs_ace *pace, char *end_of_acl) 300static 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)
243 int i; 318 int i;
244 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d", 319 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
245 pace->sid.revision, pace->sid.num_subauth, pace->type, 320 pace->sid.revision, pace->sid.num_subauth, pace->type,
246 pace->flags, pace->size)); 321 pace->flags, le16_to_cpu(pace->size)));
247 for (i = 0; i < num_subauth; ++i) { 322 for (i = 0; i < num_subauth; ++i) {
248 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, 323 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
249 le32_to_cpu(pace->sid.sub_auth[i]))); 324 le32_to_cpu(pace->sid.sub_auth[i])));
@@ -346,6 +421,28 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
346} 421}
347 422
348 423
424static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
425 struct cifs_sid *pgrpsid, __u64 nmode)
426{
427 __le16 size = 0;
428 struct cifs_acl *pnndacl;
429
430 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
431
432 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
433 pownersid, nmode, S_IRWXU);
434 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
435 pgrpsid, nmode, S_IRWXG);
436 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
437 &sid_everyone, nmode, S_IRWXO);
438
439 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
440 pndacl->num_aces = 3;
441
442 return (0);
443}
444
445
349static int parse_sid(struct cifs_sid *psid, char *end_of_acl) 446static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
350{ 447{
351 /* BB need to add parm so we can store the SID BB */ 448 /* 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,
432} 529}
433 530
434 531
532/* Convert permission bits from mode to equivalent CIFS ACL */
533static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
534 int acl_len, struct inode *inode, __u64 nmode)
535{
536 int rc = 0;
537 __u32 dacloffset;
538 __u32 ndacloffset;
539 __u32 sidsoffset;
540 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
541 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
542 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
543
544 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
545 return (-EIO);
546
547 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
548 le32_to_cpu(pntsd->osidoffset));
549 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
550 le32_to_cpu(pntsd->gsidoffset));
551
552 dacloffset = le32_to_cpu(pntsd->dacloffset);
553 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
554
555 ndacloffset = sizeof(struct cifs_ntsd);
556 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
557 ndacl_ptr->revision = dacl_ptr->revision;
558 ndacl_ptr->size = 0;
559 ndacl_ptr->num_aces = 0;
560
561 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
562
563 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
564
565 /* copy security descriptor control portion and owner and group sid */
566 copy_sec_desc(pntsd, pnntsd, sidsoffset);
567
568 return (rc);
569}
570
571
435/* Retrieve an ACL from the server */ 572/* Retrieve an ACL from the server */
436static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, 573static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
437 const char *path) 574 const char *path)
@@ -487,6 +624,64 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
487 return pntsd; 624 return pntsd;
488} 625}
489 626
627/* Set an ACL on the server */
628static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
629 struct inode *inode, const char *path)
630{
631 struct cifsFileInfo *open_file;
632 int unlock_file = FALSE;
633 int xid;
634 int rc = -EIO;
635 __u16 fid;
636 struct super_block *sb;
637 struct cifs_sb_info *cifs_sb;
638
639#ifdef CONFIG_CIFS_DEBUG2
640 cFYI(1, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
641#endif
642
643 if (!inode)
644 return (rc);
645
646 sb = inode->i_sb;
647 if (sb == NULL)
648 return (rc);
649
650 cifs_sb = CIFS_SB(sb);
651 xid = GetXid();
652
653 open_file = find_readable_file(CIFS_I(inode));
654 if (open_file) {
655 unlock_file = TRUE;
656 fid = open_file->netfid;
657 } else {
658 int oplock = FALSE;
659 /* open file */
660 rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
661 WRITE_DAC, 0, &fid, &oplock, NULL,
662 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
663 CIFS_MOUNT_MAP_SPECIAL_CHR);
664 if (rc != 0) {
665 cERROR(1, ("Unable to open file to set ACL"));
666 FreeXid(xid);
667 return (rc);
668 }
669 }
670
671 rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
672#ifdef CONFIG_CIFS_DEBUG2
673 cFYI(1, ("SetCIFSACL rc = %d", rc));
674#endif
675 if (unlock_file == TRUE)
676 atomic_dec(&open_file->wrtPending);
677 else
678 CIFSSMBClose(xid, cifs_sb->tcon, fid);
679
680 FreeXid(xid);
681
682 return (rc);
683}
684
490/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ 685/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
491void acl_to_uid_mode(struct inode *inode, const char *path) 686void acl_to_uid_mode(struct inode *inode, const char *path)
492{ 687{
@@ -510,24 +705,53 @@ void acl_to_uid_mode(struct inode *inode, const char *path)
510} 705}
511 706
512/* Convert mode bits to an ACL so we can update the ACL on the server */ 707/* Convert mode bits to an ACL so we can update the ACL on the server */
513int mode_to_acl(struct inode *inode, const char *path) 708int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
514{ 709{
515 int rc = 0; 710 int rc = 0;
516 __u32 acllen = 0; 711 __u32 acllen = 0;
517 struct cifs_ntsd *pntsd = NULL; 712 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
713 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
518 714
715#ifdef CONFIG_CIFS_DEBUG2
519 cFYI(1, ("set ACL from mode for %s", path)); 716 cFYI(1, ("set ACL from mode for %s", path));
717#endif
520 718
521 /* Get the security descriptor */ 719 /* Get the security descriptor */
522 pntsd = get_cifs_acl(&acllen, inode, path); 720 pntsd = get_cifs_acl(&acllen, inode, path);
523 721
524 /* Add/Modify the three ACEs for owner, group, everyone 722 /* Add three ACEs for owner, group, everyone getting rid of
525 while retaining the other ACEs */ 723 other ACEs as chmod disables ACEs and set the security descriptor */
526 724
527 /* Set the security descriptor */ 725 if (pntsd) {
726 /* allocate memory for the smb header,
727 set security descriptor request security descriptor
728 parameters, and secuirty descriptor itself */
528 729
730 pnntsd = kmalloc(acllen, GFP_KERNEL);
731 if (!pnntsd) {
732 cERROR(1, ("Unable to allocate security descriptor"));
733 kfree(pntsd);
734 return (-ENOMEM);
735 }
529 736
530 kfree(pntsd); 737 rc = build_sec_desc(pntsd, pnntsd, acllen, inode, nmode);
531 return rc; 738
739#ifdef CONFIG_CIFS_DEBUG2
740 cFYI(1, ("build_sec_desc rc: %d", rc));
741#endif
742
743 if (!rc) {
744 /* Set the security descriptor */
745 rc = set_cifs_acl(pnntsd, acllen, inode, path);
746#ifdef CONFIG_CIFS_DEBUG2
747 cFYI(1, ("set_cifs_acl rc: %d", rc));
748#endif
749 }
750
751 kfree(pnntsd);
752 kfree(pntsd);
753 }
754
755 return (rc);
532} 756}
533#endif /* CONFIG_CIFS_EXPERIMENTAL */ 757#endif /* CONFIG_CIFS_EXPERIMENTAL */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 093beaa3900d..e9f4ec701092 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -44,6 +44,7 @@
44#include "cifs_fs_sb.h" 44#include "cifs_fs_sb.h"
45#include <linux/mm.h> 45#include <linux/mm.h>
46#include <linux/key-type.h> 46#include <linux/key-type.h>
47#include "dns_resolve.h"
47#include "cifs_spnego.h" 48#include "cifs_spnego.h"
48#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ 49#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
49 50
@@ -96,6 +97,9 @@ cifs_read_super(struct super_block *sb, void *data,
96{ 97{
97 struct inode *inode; 98 struct inode *inode;
98 struct cifs_sb_info *cifs_sb; 99 struct cifs_sb_info *cifs_sb;
100#ifdef CONFIG_CIFS_DFS_UPCALL
101 int len;
102#endif
99 int rc = 0; 103 int rc = 0;
100 104
101 /* BB should we make this contingent on mount parm? */ 105 /* BB should we make this contingent on mount parm? */
@@ -105,6 +109,25 @@ cifs_read_super(struct super_block *sb, void *data,
105 if (cifs_sb == NULL) 109 if (cifs_sb == NULL)
106 return -ENOMEM; 110 return -ENOMEM;
107 111
112#ifdef CONFIG_CIFS_DFS_UPCALL
113 /* copy mount params to sb for use in submounts */
114 /* BB: should we move this after the mount so we
115 * do not have to do the copy on failed mounts?
116 * BB: May be it is better to do simple copy before
117 * complex operation (mount), and in case of fail
118 * just exit instead of doing mount and attempting
119 * undo it if this copy fails?*/
120 len = strlen(data);
121 cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
122 if (cifs_sb->mountdata == NULL) {
123 kfree(sb->s_fs_info);
124 sb->s_fs_info = NULL;
125 return -ENOMEM;
126 }
127 strncpy(cifs_sb->mountdata, data, len + 1);
128 cifs_sb->mountdata[len] = '\0';
129#endif
130
108 rc = cifs_mount(sb, cifs_sb, data, devname); 131 rc = cifs_mount(sb, cifs_sb, data, devname);
109 132
110 if (rc) { 133 if (rc) {
@@ -154,6 +177,12 @@ out_no_root:
154 177
155out_mount_failed: 178out_mount_failed:
156 if (cifs_sb) { 179 if (cifs_sb) {
180#ifdef CONFIG_CIFS_DFS_UPCALL
181 if (cifs_sb->mountdata) {
182 kfree(cifs_sb->mountdata);
183 cifs_sb->mountdata = NULL;
184 }
185#endif
157 if (cifs_sb->local_nls) 186 if (cifs_sb->local_nls)
158 unload_nls(cifs_sb->local_nls); 187 unload_nls(cifs_sb->local_nls);
159 kfree(cifs_sb); 188 kfree(cifs_sb);
@@ -177,6 +206,13 @@ cifs_put_super(struct super_block *sb)
177 if (rc) { 206 if (rc) {
178 cERROR(1, ("cifs_umount failed with return code %d", rc)); 207 cERROR(1, ("cifs_umount failed with return code %d", rc));
179 } 208 }
209#ifdef CONFIG_CIFS_DFS_UPCALL
210 if (cifs_sb->mountdata) {
211 kfree(cifs_sb->mountdata);
212 cifs_sb->mountdata = NULL;
213 }
214#endif
215
180 unload_nls(cifs_sb->local_nls); 216 unload_nls(cifs_sb->local_nls);
181 kfree(cifs_sb); 217 kfree(cifs_sb);
182 return; 218 return;
@@ -435,6 +471,10 @@ static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
435 struct cifs_sb_info *cifs_sb; 471 struct cifs_sb_info *cifs_sb;
436 struct cifsTconInfo *tcon; 472 struct cifsTconInfo *tcon;
437 473
474#ifdef CONFIG_CIFS_DFS_UPCALL
475 dfs_shrink_umount_helper(vfsmnt);
476#endif /* CONFIG CIFS_DFS_UPCALL */
477
438 if (!(flags & MNT_FORCE)) 478 if (!(flags & MNT_FORCE))
439 return; 479 return;
440 cifs_sb = CIFS_SB(vfsmnt->mnt_sb); 480 cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
@@ -552,7 +592,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
552 return remote_llseek(file, offset, origin); 592 return remote_llseek(file, offset, origin);
553} 593}
554 594
555static struct file_system_type cifs_fs_type = { 595struct file_system_type cifs_fs_type = {
556 .owner = THIS_MODULE, 596 .owner = THIS_MODULE,
557 .name = "cifs", 597 .name = "cifs",
558 .get_sb = cifs_get_sb, 598 .get_sb = cifs_get_sb,
@@ -1015,11 +1055,16 @@ init_cifs(void)
1015 if (rc) 1055 if (rc)
1016 goto out_unregister_filesystem; 1056 goto out_unregister_filesystem;
1017#endif 1057#endif
1058#ifdef CONFIG_CIFS_DFS_UPCALL
1059 rc = register_key_type(&key_type_dns_resolver);
1060 if (rc)
1061 goto out_unregister_key_type;
1062#endif
1018 oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd"); 1063 oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
1019 if (IS_ERR(oplockThread)) { 1064 if (IS_ERR(oplockThread)) {
1020 rc = PTR_ERR(oplockThread); 1065 rc = PTR_ERR(oplockThread);
1021 cERROR(1, ("error %d create oplock thread", rc)); 1066 cERROR(1, ("error %d create oplock thread", rc));
1022 goto out_unregister_key_type; 1067 goto out_unregister_dfs_key_type;
1023 } 1068 }
1024 1069
1025 dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd"); 1070 dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
@@ -1033,7 +1078,11 @@ init_cifs(void)
1033 1078
1034 out_stop_oplock_thread: 1079 out_stop_oplock_thread:
1035 kthread_stop(oplockThread); 1080 kthread_stop(oplockThread);
1081 out_unregister_dfs_key_type:
1082#ifdef CONFIG_CIFS_DFS_UPCALL
1083 unregister_key_type(&key_type_dns_resolver);
1036 out_unregister_key_type: 1084 out_unregister_key_type:
1085#endif
1037#ifdef CONFIG_CIFS_UPCALL 1086#ifdef CONFIG_CIFS_UPCALL
1038 unregister_key_type(&cifs_spnego_key_type); 1087 unregister_key_type(&cifs_spnego_key_type);
1039 out_unregister_filesystem: 1088 out_unregister_filesystem:
@@ -1059,6 +1108,9 @@ exit_cifs(void)
1059#ifdef CONFIG_PROC_FS 1108#ifdef CONFIG_PROC_FS
1060 cifs_proc_clean(); 1109 cifs_proc_clean();
1061#endif 1110#endif
1111#ifdef CONFIG_CIFS_DFS_UPCALL
1112 unregister_key_type(&key_type_dns_resolver);
1113#endif
1062#ifdef CONFIG_CIFS_UPCALL 1114#ifdef CONFIG_CIFS_UPCALL
1063 unregister_key_type(&cifs_spnego_key_type); 1115 unregister_key_type(&cifs_spnego_key_type);
1064#endif 1116#endif
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 2a21dc66f0de..195b14de5567 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -32,6 +32,7 @@
32#define TRUE 1 32#define TRUE 1
33#endif 33#endif
34 34
35extern struct file_system_type cifs_fs_type;
35extern const struct address_space_operations cifs_addr_ops; 36extern const struct address_space_operations cifs_addr_ops;
36extern const struct address_space_operations cifs_addr_ops_smallbuf; 37extern const struct address_space_operations cifs_addr_ops_smallbuf;
37 38
@@ -60,6 +61,10 @@ extern int cifs_setattr(struct dentry *, struct iattr *);
60 61
61extern const struct inode_operations cifs_file_inode_ops; 62extern const struct inode_operations cifs_file_inode_ops;
62extern const struct inode_operations cifs_symlink_inode_ops; 63extern const struct inode_operations cifs_symlink_inode_ops;
64extern struct list_head cifs_dfs_automount_list;
65extern struct inode_operations cifs_dfs_referral_inode_operations;
66
67
63 68
64/* Functions related to files and directories */ 69/* Functions related to files and directories */
65extern const struct file_operations cifs_file_ops; 70extern const struct file_operations cifs_file_ops;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1fde2197ad76..5d32d8ddc82e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/cifsglob.h 2 * fs/cifs/cifsglob.h
3 * 3 *
4 * Copyright (C) International Business Machines Corp., 2002,2007 4 * Copyright (C) International Business Machines Corp., 2002,2008
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * Jeremy Allison (jra@samba.org) 6 * Jeremy Allison (jra@samba.org)
7 * 7 *
@@ -70,14 +70,6 @@
70#endif 70#endif
71 71
72/* 72/*
73 * This information is kept on every Server we know about.
74 *
75 * Some things to note:
76 *
77 */
78#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
79
80/*
81 * CIFS vfs client Status information (based on what we know.) 73 * CIFS vfs client Status information (based on what we know.)
82 */ 74 */
83 75
@@ -460,6 +452,37 @@ struct dir_notify_req {
460 struct file *pfile; 452 struct file *pfile;
461}; 453};
462 454
455struct dfs_info3_param {
456 int flags; /* DFSREF_REFERRAL_SERVER, DFSREF_STORAGE_SERVER*/
457 int PathConsumed;
458 int server_type;
459 int ref_flag;
460 char *path_name;
461 char *node_name;
462};
463
464static inline void free_dfs_info_param(struct dfs_info3_param *param)
465{
466 if (param) {
467 kfree(param->path_name);
468 kfree(param->node_name);
469 kfree(param);
470 }
471}
472
473static inline void free_dfs_info_array(struct dfs_info3_param *param,
474 int number_of_items)
475{
476 int i;
477 if ((number_of_items == 0) || (param == NULL))
478 return;
479 for (i = 0; i < number_of_items; i++) {
480 kfree(param[i].path_name);
481 kfree(param[i].node_name);
482 }
483 kfree(param);
484}
485
463#define MID_FREE 0 486#define MID_FREE 0
464#define MID_REQUEST_ALLOCATED 1 487#define MID_REQUEST_ALLOCATED 1
465#define MID_REQUEST_SUBMITTED 2 488#define MID_REQUEST_SUBMITTED 2
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index dbe6b846f37f..47f79504f57b 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -237,6 +237,9 @@
237 | DELETE | READ_CONTROL | WRITE_DAC \ 237 | DELETE | READ_CONTROL | WRITE_DAC \
238 | WRITE_OWNER | SYNCHRONIZE) 238 | WRITE_OWNER | SYNCHRONIZE)
239 239
240#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \
241 | READ_CONTROL | SYNCHRONIZE)
242
240 243
241/* 244/*
242 * Invalid readdir handle 245 * Invalid readdir handle
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 8350eec49663..2f09f565a3d9 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/cifsproto.h 2 * fs/cifs/cifsproto.h
3 * 3 *
4 * Copyright (c) International Business Machines Corp., 2002,2007 4 * Copyright (c) International Business Machines Corp., 2002,2008
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * This library is free software; you can redistribute it and/or modify 7 * 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,
97 const unsigned char *search_path, 97 const unsigned char *search_path,
98 struct super_block *sb, int xid); 98 struct super_block *sb, int xid);
99extern void acl_to_uid_mode(struct inode *inode, const char *search_path); 99extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
100extern int mode_to_acl(struct inode *inode, const char *path); 100extern int mode_to_acl(struct inode *inode, const char *path, __u64);
101 101
102extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, 102extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
103 const char *); 103 const char *);
104extern int cifs_umount(struct super_block *, struct cifs_sb_info *); 104extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
105#ifdef CONFIG_CIFS_DFS_UPCALL
106extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
107#endif
105void cifs_proc_init(void); 108void cifs_proc_init(void);
106void cifs_proc_clean(void); 109void cifs_proc_clean(void);
107 110
@@ -153,7 +156,7 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
153 const char *old_path, 156 const char *old_path,
154 const struct nls_table *nls_codepage, 157 const struct nls_table *nls_codepage,
155 unsigned int *pnum_referrals, 158 unsigned int *pnum_referrals,
156 unsigned char **preferrals, 159 struct dfs_info3_param **preferrals,
157 int remap); 160 int remap);
158extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, 161extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
159 struct super_block *sb, struct smb_vol *vol); 162 struct super_block *sb, struct smb_vol *vol);
@@ -342,6 +345,8 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
342 const struct nls_table *nls_codepage, int remap_special_chars); 345 const struct nls_table *nls_codepage, int remap_special_chars);
343extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, 346extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
344 __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen); 347 __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
348extern int CIFSSMBSetCIFSACL(const int, struct cifsTconInfo *, __u16,
349 struct cifs_ntsd *, __u32);
345extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, 350extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
346 const unsigned char *searchName, 351 const unsigned char *searchName,
347 char *acl_inf, const int buflen, const int acl_type, 352 char *acl_inf, const int buflen, const int acl_type,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9e8a6bef029a..9409524e4bf8 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3156,6 +3156,71 @@ qsec_out:
3156/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ 3156/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3157 return rc; 3157 return rc;
3158} 3158}
3159
3160int
3161CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3162 struct cifs_ntsd *pntsd, __u32 acllen)
3163{
3164 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3165 int rc = 0;
3166 int bytes_returned = 0;
3167 SET_SEC_DESC_REQ *pSMB = NULL;
3168 NTRANSACT_RSP *pSMBr = NULL;
3169
3170setCifsAclRetry:
3171 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3172 (void **) &pSMBr);
3173 if (rc)
3174 return (rc);
3175
3176 pSMB->MaxSetupCount = 0;
3177 pSMB->Reserved = 0;
3178
3179 param_count = 8;
3180 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3181 data_count = acllen;
3182 data_offset = param_offset + param_count;
3183 byte_count = 3 /* pad */ + param_count;
3184
3185 pSMB->DataCount = cpu_to_le32(data_count);
3186 pSMB->TotalDataCount = pSMB->DataCount;
3187 pSMB->MaxParameterCount = cpu_to_le32(4);
3188 pSMB->MaxDataCount = cpu_to_le32(16384);
3189 pSMB->ParameterCount = cpu_to_le32(param_count);
3190 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3191 pSMB->TotalParameterCount = pSMB->ParameterCount;
3192 pSMB->DataOffset = cpu_to_le32(data_offset);
3193 pSMB->SetupCount = 0;
3194 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3195 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3196
3197 pSMB->Fid = fid; /* file handle always le */
3198 pSMB->Reserved2 = 0;
3199 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3200
3201 if (pntsd && acllen) {
3202 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3203 (char *) pntsd,
3204 acllen);
3205 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3206
3207 } else
3208 pSMB->hdr.smb_buf_length += byte_count;
3209
3210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3212
3213 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3214 if (rc)
3215 cFYI(1, ("Set CIFS ACL returned %d", rc));
3216 cifs_buf_release(pSMB);
3217
3218 if (rc == -EAGAIN)
3219 goto setCifsAclRetry;
3220
3221 return (rc);
3222}
3223
3159#endif /* CONFIG_CIFS_EXPERIMENTAL */ 3224#endif /* CONFIG_CIFS_EXPERIMENTAL */
3160 3225
3161/* Legacy Query Path Information call for lookup to old servers such 3226/* Legacy Query Path Information call for lookup to old servers such
@@ -5499,7 +5564,7 @@ SetEARetry:
5499 else 5564 else
5500 name_len = strnlen(ea_name, 255); 5565 name_len = strnlen(ea_name, 255);
5501 5566
5502 count = sizeof(*parm_data) + ea_value_len + name_len + 1; 5567 count = sizeof(*parm_data) + ea_value_len + name_len;
5503 pSMB->MaxParameterCount = cpu_to_le16(2); 5568 pSMB->MaxParameterCount = cpu_to_le16(2);
5504 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ 5569 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5505 pSMB->MaxSetupCount = 0; 5570 pSMB->MaxSetupCount = 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index fd9147cdb5a9..65d0ba72e78f 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/connect.c 2 * fs/cifs/connect.c
3 * 3 *
4 * Copyright (C) International Business Machines Corp., 2002,2007 4 * Copyright (C) International Business Machines Corp., 2002,2008
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * This library is free software; you can redistribute it and/or modify 7 * 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,
1410 const char *old_path, const struct nls_table *nls_codepage, 1410 const char *old_path, const struct nls_table *nls_codepage,
1411 int remap) 1411 int remap)
1412{ 1412{
1413 unsigned char *referrals = NULL; 1413 struct dfs_info3_param *referrals = NULL;
1414 unsigned int num_referrals; 1414 unsigned int num_referrals;
1415 int rc = 0; 1415 int rc = 0;
1416 1416
@@ -1429,12 +1429,14 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1429int 1429int
1430get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, 1430get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1431 const struct nls_table *nls_codepage, unsigned int *pnum_referrals, 1431 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1432 unsigned char **preferrals, int remap) 1432 struct dfs_info3_param **preferrals, int remap)
1433{ 1433{
1434 char *temp_unc; 1434 char *temp_unc;
1435 int rc = 0; 1435 int rc = 0;
1436 unsigned char *targetUNCs;
1436 1437
1437 *pnum_referrals = 0; 1438 *pnum_referrals = 0;
1439 *preferrals = NULL;
1438 1440
1439 if (pSesInfo->ipc_tid == 0) { 1441 if (pSesInfo->ipc_tid == 0) {
1440 temp_unc = kmalloc(2 /* for slashes */ + 1442 temp_unc = kmalloc(2 /* for slashes */ +
@@ -1454,8 +1456,10 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1454 kfree(temp_unc); 1456 kfree(temp_unc);
1455 } 1457 }
1456 if (rc == 0) 1458 if (rc == 0)
1457 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, 1459 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
1458 pnum_referrals, nls_codepage, remap); 1460 pnum_referrals, nls_codepage, remap);
1461 /* BB map targetUNCs to dfs_info3 structures, here or
1462 in CIFSGetDFSRefer BB */
1459 1463
1460 return rc; 1464 return rc;
1461} 1465}
@@ -1964,7 +1968,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1964 1968
1965 if (existingCifsSes) { 1969 if (existingCifsSes) {
1966 pSesInfo = existingCifsSes; 1970 pSesInfo = existingCifsSes;
1967 cFYI(1, ("Existing smb sess found")); 1971 cFYI(1, ("Existing smb sess found (status=%d)",
1972 pSesInfo->status));
1973 down(&pSesInfo->sesSem);
1974 if (pSesInfo->status == CifsNeedReconnect) {
1975 cFYI(1, ("Session needs reconnect"));
1976 rc = cifs_setup_session(xid, pSesInfo,
1977 cifs_sb->local_nls);
1978 }
1979 up(&pSesInfo->sesSem);
1968 } else if (!rc) { 1980 } else if (!rc) {
1969 cFYI(1, ("Existing smb sess not found")); 1981 cFYI(1, ("Existing smb sess not found"));
1970 pSesInfo = sesInfoAlloc(); 1982 pSesInfo = sesInfoAlloc();
@@ -3514,7 +3526,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3514 sesInfoFree(ses); 3526 sesInfoFree(ses);
3515 3527
3516 FreeXid(xid); 3528 FreeXid(xid);
3517 return rc; /* BB check if we should always return zero here */ 3529 return rc;
3518} 3530}
3519 3531
3520int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, 3532int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 37dc97af1487..699ec1198409 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -517,12 +517,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
517 d_add(direntry, NULL); 517 d_add(direntry, NULL);
518 /* if it was once a directory (but how can we tell?) we could do 518 /* if it was once a directory (but how can we tell?) we could do
519 shrink_dcache_parent(direntry); */ 519 shrink_dcache_parent(direntry); */
520 } else { 520 } else if (rc != -EACCES) {
521 cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s", 521 cERROR(1, ("Unexpected lookup error %d", rc));
522 rc, full_path)); 522 /* We special case check for Access Denied - since that
523 /* BB special case check for Access Denied - watch security 523 is a common return code */
524 exposure of returning dir info implicitly via different rc
525 if file exists or not but no access BB */
526 } 524 }
527 525
528 kfree(full_path); 526 kfree(full_path);
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
new file mode 100644
index 000000000000..ef7f43824347
--- /dev/null
+++ b/fs/cifs/dns_resolve.c
@@ -0,0 +1,124 @@
1/*
2 * fs/cifs/dns_resolve.c
3 *
4 * Copyright (c) 2007 Igor Mammedov
5 * Author(s): Igor Mammedov (niallain@gmail.com)
6 * Steve French (sfrench@us.ibm.com)
7 *
8 * Contains the CIFS DFS upcall routines used for hostname to
9 * IP address translation.
10 *
11 * This library is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published
13 * by the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
19 * the GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include <keys/user-type.h>
27#include "dns_resolve.h"
28#include "cifsglob.h"
29#include "cifsproto.h"
30#include "cifs_debug.h"
31
32static int dns_resolver_instantiate(struct key *key, const void *data,
33 size_t datalen)
34{
35 int rc = 0;
36 char *ip;
37
38 ip = kmalloc(datalen+1, GFP_KERNEL);
39 if (!ip)
40 return -ENOMEM;
41
42 memcpy(ip, data, datalen);
43 ip[datalen] = '\0';
44
45 rcu_assign_pointer(key->payload.data, ip);
46
47 return rc;
48}
49
50struct key_type key_type_dns_resolver = {
51 .name = "dns_resolver",
52 .def_datalen = sizeof(struct in_addr),
53 .describe = user_describe,
54 .instantiate = dns_resolver_instantiate,
55 .match = user_match,
56};
57
58
59/* Resolves server name to ip address.
60 * input:
61 * unc - server UNC
62 * output:
63 * *ip_addr - pointer to server ip, caller responcible for freeing it.
64 * return 0 on success
65 */
66int
67dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
68{
69 int rc = -EAGAIN;
70 struct key *rkey;
71 char *name;
72 int len;
73
74 if (!ip_addr || !unc)
75 return -EINVAL;
76
77 /* search for server name delimiter */
78 len = strlen(unc);
79 if (len < 3) {
80 cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc));
81 return -EINVAL;
82 }
83 len -= 2;
84 name = memchr(unc+2, '\\', len);
85 if (!name) {
86 cFYI(1, ("%s: probably server name is whole unc: %s",
87 __FUNCTION__, unc));
88 } else {
89 len = (name - unc) - 2/* leading // */;
90 }
91
92 name = kmalloc(len+1, GFP_KERNEL);
93 if (!name) {
94 rc = -ENOMEM;
95 return rc;
96 }
97 memcpy(name, unc+2, len);
98 name[len] = 0;
99
100 rkey = request_key(&key_type_dns_resolver, name, "");
101 if (!IS_ERR(rkey)) {
102 len = strlen(rkey->payload.data);
103 *ip_addr = kmalloc(len+1, GFP_KERNEL);
104 if (*ip_addr) {
105 memcpy(*ip_addr, rkey->payload.data, len);
106 (*ip_addr)[len] = '\0';
107 cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__,
108 rkey->description,
109 *ip_addr
110 ));
111 rc = 0;
112 } else {
113 rc = -ENOMEM;
114 }
115 key_put(rkey);
116 } else {
117 cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name));
118 }
119
120 kfree(name);
121 return rc;
122}
123
124
diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h
new file mode 100644
index 000000000000..073fdc3db419
--- /dev/null
+++ b/fs/cifs/dns_resolve.h
@@ -0,0 +1,32 @@
1/*
2 * fs/cifs/dns_resolve.h -- DNS Resolver upcall management for CIFS DFS
3 * Handles host name to IP address resolution
4 *
5 * Copyright (c) International Business Machines Corp., 2008
6 * Author(s): Steve French (sfrench@us.ibm.com)
7 *
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
16 * the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef _DNS_RESOLVE_H
24#define _DNS_RESOLVE_H
25
26#ifdef __KERNEL__
27#include <linux/key-type.h>
28extern struct key_type key_type_dns_resolver;
29extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
30#endif /* KERNEL */
31
32#endif /* _DNS_RESOLVE_H */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index dd26e2759b17..5f7c374ae89c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1179,12 +1179,10 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
1179 atomic_dec(&open_file->wrtPending); 1179 atomic_dec(&open_file->wrtPending);
1180 /* Does mm or vfs already set times? */ 1180 /* Does mm or vfs already set times? */
1181 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); 1181 inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
1182 if ((bytes_written > 0) && (offset)) { 1182 if ((bytes_written > 0) && (offset))
1183 rc = 0; 1183 rc = 0;
1184 } else if (bytes_written < 0) { 1184 else if (bytes_written < 0)
1185 if (rc != -EBADF) 1185 rc = bytes_written;
1186 rc = bytes_written;
1187 }
1188 } else { 1186 } else {
1189 cFYI(1, ("No writeable filehandles for inode")); 1187 cFYI(1, ("No writeable filehandles for inode"));
1190 rc = -EIO; 1188 rc = -EIO;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index e915eb1d2e66..d9567ba2960b 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -54,9 +54,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
54 MAX_TREE_SIZE + 1) + 54 MAX_TREE_SIZE + 1) +
55 strnlen(search_path, MAX_PATHCONF) + 1, 55 strnlen(search_path, MAX_PATHCONF) + 1,
56 GFP_KERNEL); 56 GFP_KERNEL);
57 if (tmp_path == NULL) { 57 if (tmp_path == NULL)
58 return -ENOMEM; 58 return -ENOMEM;
59 } 59
60 /* have to skip first of the double backslash of 60 /* have to skip first of the double backslash of
61 UNC name */ 61 UNC name */
62 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); 62 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
@@ -511,7 +511,8 @@ int cifs_get_inode_info(struct inode **pinode,
511 } 511 }
512 512
513 spin_lock(&inode->i_lock); 513 spin_lock(&inode->i_lock);
514 if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) { 514 if (is_size_safe_to_change(cifsInfo,
515 le64_to_cpu(pfindData->EndOfFile))) {
515 /* can not safely shrink the file size here if the 516 /* can not safely shrink the file size here if the
516 client is writing to it due to potential races */ 517 client is writing to it due to potential races */
517 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); 518 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
@@ -931,7 +932,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
931 (CIFS_UNIX_POSIX_PATH_OPS_CAP & 932 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
932 le64_to_cpu(pTcon->fsUnixInfo.Capability))) { 933 le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
933 u32 oplock = 0; 934 u32 oplock = 0;
934 FILE_UNIX_BASIC_INFO * pInfo = 935 FILE_UNIX_BASIC_INFO *pInfo =
935 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 936 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
936 if (pInfo == NULL) { 937 if (pInfo == NULL) {
937 rc = -ENOMEM; 938 rc = -ENOMEM;
@@ -1607,7 +1608,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1607 CIFS_MOUNT_MAP_SPECIAL_CHR); 1608 CIFS_MOUNT_MAP_SPECIAL_CHR);
1608 else if (attrs->ia_valid & ATTR_MODE) { 1609 else if (attrs->ia_valid & ATTR_MODE) {
1609 rc = 0; 1610 rc = 0;
1610 if ((mode & S_IWUGO) == 0) /* not writeable */ { 1611#ifdef CONFIG_CIFS_EXPERIMENTAL
1612 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
1613 rc = mode_to_acl(direntry->d_inode, full_path, mode);
1614 else if ((mode & S_IWUGO) == 0) {
1615#else
1616 if ((mode & S_IWUGO) == 0) {
1617#endif
1618 /* not writeable */
1611 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 1619 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
1612 set_dosattr = TRUE; 1620 set_dosattr = TRUE;
1613 time_buf.Attributes = 1621 time_buf.Attributes =
@@ -1626,10 +1634,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1626 if (time_buf.Attributes == 0) 1634 if (time_buf.Attributes == 0)
1627 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); 1635 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
1628 } 1636 }
1629 /* BB to be implemented - 1637#ifdef CONFIG_CIFS_EXPERIMENTAL
1630 via Windows security descriptors or streams */ 1638 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
1631 /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid, 1639 mode_to_acl(direntry->d_inode, full_path, mode);
1632 cifs_sb->local_nls); */ 1640#endif
1633 } 1641 }
1634 1642
1635 if (attrs->ia_valid & ATTR_ATIME) { 1643 if (attrs->ia_valid & ATTR_ATIME) {
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 11f265726db7..1d6fb01b8e6d 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/link.c 2 * fs/cifs/link.c
3 * 3 *
4 * Copyright (C) International Business Machines Corp., 2002,2003 4 * Copyright (C) International Business Machines Corp., 2002,2008
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * This library is free software; you can redistribute it and/or modify 7 * 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)
236 char *full_path = NULL; 236 char *full_path = NULL;
237 char *tmp_path = NULL; 237 char *tmp_path = NULL;
238 char *tmpbuffer; 238 char *tmpbuffer;
239 unsigned char *referrals = NULL;
240 unsigned int num_referrals = 0;
241 int len; 239 int len;
242 __u16 fid; 240 __u16 fid;
243 241
@@ -297,8 +295,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
297 cFYI(1, ("Error closing junction point " 295 cFYI(1, ("Error closing junction point "
298 "(open for ioctl)")); 296 "(open for ioctl)"));
299 } 297 }
298 /* BB unwind this long, nested function, or remove BB */
300 if (rc == -EIO) { 299 if (rc == -EIO) {
301 /* Query if DFS Junction */ 300 /* Query if DFS Junction */
301 unsigned int num_referrals = 0;
302 struct dfs_info3_param *refs = NULL;
302 tmp_path = 303 tmp_path =
303 kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, 304 kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
304 GFP_KERNEL); 305 GFP_KERNEL);
@@ -310,7 +311,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
310 rc = get_dfs_path(xid, pTcon->ses, 311 rc = get_dfs_path(xid, pTcon->ses,
311 tmp_path, 312 tmp_path,
312 cifs_sb->local_nls, 313 cifs_sb->local_nls,
313 &num_referrals, &referrals, 314 &num_referrals, &refs,
314 cifs_sb->mnt_cifs_flags & 315 cifs_sb->mnt_cifs_flags &
315 CIFS_MOUNT_MAP_SPECIAL_CHR); 316 CIFS_MOUNT_MAP_SPECIAL_CHR);
316 cFYI(1, ("Get DFS for %s rc = %d ", 317 cFYI(1, ("Get DFS for %s rc = %d ",
@@ -320,14 +321,13 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
320 else { 321 else {
321 cFYI(1, ("num referral: %d", 322 cFYI(1, ("num referral: %d",
322 num_referrals)); 323 num_referrals));
323 if (referrals) { 324 if (refs && refs->path_name) {
324 cFYI(1,("referral string: %s", referrals));
325 strncpy(tmpbuffer, 325 strncpy(tmpbuffer,
326 referrals, 326 refs->path_name,
327 len-1); 327 len-1);
328 } 328 }
329 } 329 }
330 kfree(referrals); 330 kfree(refs);
331 kfree(tmp_path); 331 kfree(tmp_path);
332} 332}
333 /* BB add code like else decode referrals 333 /* BB add code like else decode referrals
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index d0cb469daab7..d2153abcba6d 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -528,9 +528,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
528 rc = -EOVERFLOW; 528 rc = -EOVERFLOW;
529 goto ssetup_exit; 529 goto ssetup_exit;
530 } 530 }
531 ses->server->mac_signing_key.len = msg->sesskey_len; 531 if (first_time) {
532 memcpy(ses->server->mac_signing_key.data.krb5, msg->data, 532 ses->server->mac_signing_key.len = msg->sesskey_len;
533 msg->sesskey_len); 533 memcpy(ses->server->mac_signing_key.data.krb5,
534 msg->data, msg->sesskey_len);
535 }
534 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; 536 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
535 capabilities |= CAP_EXTENDED_SECURITY; 537 capabilities |= CAP_EXTENDED_SECURITY;
536 pSMB->req.Capabilities = cpu_to_le32(capabilities); 538 pSMB->req.Capabilities = cpu_to_le32(capabilities);
@@ -540,7 +542,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
540 542
541 if (ses->capabilities & CAP_UNICODE) { 543 if (ses->capabilities & CAP_UNICODE) {
542 /* unicode strings must be word aligned */ 544 /* unicode strings must be word aligned */
543 if (iov[0].iov_len % 2) { 545 if ((iov[0].iov_len + iov[1].iov_len) % 2) {
544 *bcc_ptr = 0; 546 *bcc_ptr = 0;
545 bcc_ptr++; 547 bcc_ptr++;
546 } 548 }