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 | |
| 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
| -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 | } |
