diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-27 02:01:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-27 02:01:20 -0500 |
commit | ef3f2de2b5496f721b12f21a157e19eac816394b (patch) | |
tree | e2aa39d46714e7956ed12b85cd9490ef327abaff /fs | |
parent | 1c7c2cdec3a6b2873439096983794a550d7ff65b (diff) | |
parent | 366781c19635d861f43ff5e03388a3873ec912d9 (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/Kconfig | 39 | ||||
-rw-r--r-- | fs/cifs/CHANGES | 5 | ||||
-rw-r--r-- | fs/cifs/Makefile | 2 | ||||
-rw-r--r-- | fs/cifs/README | 28 | ||||
-rw-r--r-- | fs/cifs/TODO | 14 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 377 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 6 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 240 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 56 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 41 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 11 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 67 | ||||
-rw-r--r-- | fs/cifs/connect.c | 24 | ||||
-rw-r--r-- | fs/cifs/dir.c | 10 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.c | 124 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.h | 32 | ||||
-rw-r--r-- | fs/cifs/file.c | 8 | ||||
-rw-r--r-- | fs/cifs/inode.c | 26 | ||||
-rw-r--r-- | fs/cifs/link.c | 16 | ||||
-rw-r--r-- | fs/cifs/sess.c | 10 |
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 | ||
1911 | config CIFS_STATS | 1913 | config 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 | ||
2024 | config 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 | |||
2021 | config NCP_FS | 2034 | config 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 | |||
3 | Fix oops on second mount to server when null auth is used. | 3 | Fix oops on second mount to server when null auth is used. |
4 | Enable experimental Kerberos support. Return writebehind errors on flush | 4 | Enable experimental Kerberos support. Return writebehind errors on flush |
5 | and sync so that events like out of disk space get reported properly on | 5 | and sync so that events like out of disk space get reported properly on |
6 | cached files. | 6 | cached files. Fix setxattr failure to certain Samba versions. Fix mount |
7 | of second share to disconnected server session (autoreconnect on this). | ||
8 | Add ability to modify cifs acls for handling chmod (when mounted with | ||
9 | cifsacl flag). | ||
7 | 10 | ||
8 | Version 1.51 | 11 | Version 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 | ||
11 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | 11 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o |
12 | |||
13 | cifs-$(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 | |||
56 | similar files reside (usually /sbin). Although the helper software is not | 56 | similar files reside (usually /sbin). Although the helper software is not |
57 | required, mount.cifs is recommended. Eventually the Samba 3.0 utility program | 57 | required, 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 |
59 | users who are used to Windows e.g. net use <mount point> <UNC name or cifs URL> | 59 | users who are used to Windows e.g. |
60 | net use <mount point> <UNC name or cifs URL> | ||
60 | Note that running the Winbind pam/nss module (logon service) on all of your | 61 | Note that running the Winbind pam/nss module (logon service) on all of your |
61 | Linux clients is useful in mapping Uids and Gids consistently across the | 62 | Linux clients is useful in mapping Uids and Gids consistently across the |
62 | domain to the proper network user. The mount.cifs mount helper can be | 63 | 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: | |||
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 |
491 | hard Retry file operations if server is not responding | ||
492 | soft Limit retries to unresponsive servers (usually only | ||
493 | one retry) before returning an error. (default) | ||
488 | 494 | ||
489 | The mount.cifs mount helper also accepts a few mount options before -o | 495 | The mount.cifs mount helper also accepts a few mount options before -o |
490 | including: | 496 | including: |
@@ -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 | ||
627 | Also note that "cat /proc/fs/cifs/DebugData" will display information about | 633 | Also note that "cat /proc/fs/cifs/DebugData" will display information about |
628 | the active sessions and the shares that are mounted. | 634 | the active sessions and the shares that are mounted. |
629 | Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled | 635 | Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is |
630 | but requires a user space helper (from the Samba project). NTLM and NTLMv2 and | 636 | on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and |
631 | LANMAN support do not require this helpr. | 637 | LANMAN 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 @@ | |||
1 | Version 1.49 April 26, 2007 | 1 | Version 1.52 January 3, 2008 |
2 | 2 | ||
3 | A Partial List of Missing Features | 3 | A Partial List of Missing Features |
4 | ================================== | 4 | ================================== |
@@ -16,16 +16,14 @@ SecurityDescriptors | |||
16 | c) Better pam/winbind integration (e.g. to handle uid mapping | 16 | c) Better pam/winbind integration (e.g. to handle uid mapping |
17 | better) | 17 | better) |
18 | 18 | ||
19 | d) Verify that Kerberos signing works | 19 | d) Cleanup now unneeded SessSetup code in |
20 | |||
21 | e) Cleanup now unneeded SessSetup code in | ||
22 | fs/cifs/connect.c and add back in NTLMSSP code if any servers | 20 | fs/cifs/connect.c and add back in NTLMSSP code if any servers |
23 | need it | 21 | need it |
24 | 22 | ||
25 | f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup | 23 | e) ms-dfs and ms-dfs host name resolution cleanup |
26 | used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM | 24 | |
27 | and raw NTLMSSP already. This is important when enabling | 25 | f) fix NTLMv2 signing when two mounts with different users to same |
28 | extended security and mounting to Windows 2003 Servers | 26 | server. |
29 | 27 | ||
30 | g) Directory entry caching relies on a 1 second timer, rather than | 28 | g) Directory entry caching relies on a 1 second timer, rather than |
31 | using FindNotify or equivalent. - (started) | 29 | using 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 | |||
26 | LIST_HEAD(cifs_dfs_automount_list); | ||
27 | |||
28 | /* | ||
29 | * DFS functions | ||
30 | */ | ||
31 | |||
32 | void 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 | */ | ||
50 | static 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 | */ | ||
111 | static 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 | |||
187 | compose_mount_options_out: | ||
188 | kfree(srvIP); | ||
189 | return mountdata; | ||
190 | } | ||
191 | |||
192 | |||
193 | static 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 | |||
215 | static 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 | |||
255 | static 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 | |||
283 | static 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 | |||
293 | static void* | ||
294 | cifs_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 | |||
363 | out: | ||
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); | ||
369 | out_err: | ||
370 | path_release(nd); | ||
371 | goto out; | ||
372 | } | ||
373 | |||
374 | struct 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 | ||
131 | out: | 133 | out: |
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 */ | ||
134 | static 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 | ||
271 | static __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 |
225 | static void dump_ace(struct cifs_ace *pace, char *end_of_acl) | 300 | 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) | |||
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 | ||
424 | static 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 | |||
349 | static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | 446 | static 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 */ | ||
533 | static 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 */ |
436 | static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, | 573 | static 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 */ | ||
628 | static 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 */ |
491 | void acl_to_uid_mode(struct inode *inode, const char *path) | 686 | void 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 */ |
513 | int mode_to_acl(struct inode *inode, const char *path) | 708 | int 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 | ||
155 | out_mount_failed: | 178 | out_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 | ||
555 | static struct file_system_type cifs_fs_type = { | 595 | struct 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 | ||
35 | extern struct file_system_type cifs_fs_type; | ||
35 | extern const struct address_space_operations cifs_addr_ops; | 36 | extern const struct address_space_operations cifs_addr_ops; |
36 | extern const struct address_space_operations cifs_addr_ops_smallbuf; | 37 | extern 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 | ||
61 | extern const struct inode_operations cifs_file_inode_ops; | 62 | extern const struct inode_operations cifs_file_inode_ops; |
62 | extern const struct inode_operations cifs_symlink_inode_ops; | 63 | extern const struct inode_operations cifs_symlink_inode_ops; |
64 | extern struct list_head cifs_dfs_automount_list; | ||
65 | extern 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 */ |
65 | extern const struct file_operations cifs_file_ops; | 70 | extern 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 | ||
455 | struct 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 | |||
464 | static 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 | |||
473 | static 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); |
99 | extern void acl_to_uid_mode(struct inode *inode, const char *search_path); | 99 | extern void acl_to_uid_mode(struct inode *inode, const char *search_path); |
100 | extern int mode_to_acl(struct inode *inode, const char *path); | 100 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); |
101 | 101 | ||
102 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 102 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, |
103 | const char *); | 103 | const char *); |
104 | extern int cifs_umount(struct super_block *, struct cifs_sb_info *); | 104 | extern int cifs_umount(struct super_block *, struct cifs_sb_info *); |
105 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
106 | extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt); | ||
107 | #endif | ||
105 | void cifs_proc_init(void); | 108 | void cifs_proc_init(void); |
106 | void cifs_proc_clean(void); | 109 | void 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); |
158 | extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | 161 | extern 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); |
343 | extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, | 346 | extern 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); |
348 | extern int CIFSSMBSetCIFSACL(const int, struct cifsTconInfo *, __u16, | ||
349 | struct cifs_ntsd *, __u32); | ||
345 | extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, | 350 | extern 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 | |||
3160 | int | ||
3161 | CIFSSMBSetCIFSACL(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 | |||
3170 | setCifsAclRetry: | ||
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, | |||
1429 | int | 1429 | int |
1430 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 1430 | get_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 | ||
3520 | int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | 3532 | int 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 | |||
32 | static 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 | |||
50 | struct 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 | */ | ||
66 | int | ||
67 | dns_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> | ||
28 | extern struct key_type key_type_dns_resolver; | ||
29 | extern 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 | } |