aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-12 14:11:39 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-12 14:11:39 -0500
commit46015977e70f672ae6b20a1b5fb1e361208365ba (patch)
treee3be0785eff90cc8023cd1ea03fc22d3dcf37f41 /fs/cifs
parent92d140e21f1ce8cf99320afbbcad73879128e6dc (diff)
parent9b8f5f573770f33b28c45255ac82e6457278c782 (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: (21 commits) [CIFS] fix oops on second mount to same server when null auth is used [CIFS] Fix stale mode after readdir when cifsacl specified [CIFS] add mode to acl conversion helper function [CIFS] Fix incorrect mode when ACL had deny access control entries [CIFS] Add uid to key description so krb can handle user mounts [CIFS] Fix walking out end of cifs dacl [CIFS] Add upcall files for cifs to use spnego/kerberos [CIFS] add OIDs for KRB5 and MSKRB5 to ASN1 parsing routines [CIFS] Register and unregister cifs_spnego_key_type on module init/exit [CIFS] implement upcalls for SPNEGO blob via keyctl API [CIFS] allow cifs_calc_signature2 to deal with a zero length iovec [CIFS] If no Access Control Entries, set mode perm bits to zero [CIFS] when mount helper missing fix slash wrong direction in share [CIFS] Don't request too much permission when reading an ACL [CIFS] enable get mode from ACL when cifsacl mount option specified [CIFS] ACL support part 8 [CIFS] acl support part 7 [CIFS] acl support part 6 [CIFS] acl support part 6 [CIFS] remove unused funtion compile warning when experimental off ...
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/CHANGES11
-rw-r--r--fs/cifs/Makefile7
-rw-r--r--fs/cifs/asn1.c35
-rw-r--r--fs/cifs/cifs_spnego.c128
-rw-r--r--fs/cifs/cifs_spnego.h46
-rw-r--r--fs/cifs/cifsacl.c346
-rw-r--r--fs/cifs/cifsacl.h17
-rw-r--r--fs/cifs/cifsencrypt.c9
-rw-r--r--fs/cifs/cifsfs.c17
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifspdu.h40
-rw-r--r--fs/cifs/cifsproto.h11
-rw-r--r--fs/cifs/cifssmb.c64
-rw-r--r--fs/cifs/connect.c4
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/cifs/file.c31
-rw-r--r--fs/cifs/inode.c15
-rw-r--r--fs/cifs/md5.c8
-rw-r--r--fs/cifs/misc.c10
-rw-r--r--fs/cifs/netmisc.c54
-rw-r--r--fs/cifs/readdir.c10
-rw-r--r--fs/cifs/smbencrypt.c18
-rw-r--r--fs/cifs/xattr.c11
23 files changed, 726 insertions, 170 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 3d419163c3d3..64dd22239b21 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,7 @@
1Version 1.52
2------------
3Fix oops on second mount to server when null auth is used.
4
1Version 1.51 5Version 1.51
2------------ 6------------
3Fix memory leak in statfs when mounted to very old servers (e.g. 7Fix memory leak in statfs when mounted to very old servers (e.g.
@@ -12,7 +16,12 @@ leak that causes cifsd not to stop and rmmod to fail to cleanup
12cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on 16cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on
13bigendian architectures. Fix possible memory corruption when 17bigendian architectures. Fix possible memory corruption when
14EAGAIN returned on kern_recvmsg. Return better error if server 18EAGAIN returned on kern_recvmsg. Return better error if server
15requires packet signing but client has disabled it. 19requires packet signing but client has disabled it. When mounted
20with cifsacl mount option - mode bits are approximated based
21on the contents of the ACL of the file or directory. When cifs
22mount helper is missing convert make sure that UNC name
23has backslash (not forward slash) between ip address of server
24and the share name.
16 25
17Version 1.50 26Version 1.50
18------------ 27------------
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index ff6ba8d823f0..45e42fb97c19 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -3,4 +3,9 @@
3# 3#
4obj-$(CONFIG_CIFS) += cifs.o 4obj-$(CONFIG_CIFS) += cifs.o
5 5
6cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o cifsacl.o 6cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
7 link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
8 md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o \
9 readdir.o ioctl.o sess.o export.o cifsacl.o
10
11cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
index 2a01f3ef96a0..bcda2c6b6a04 100644
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -77,8 +77,12 @@
77 77
78#define SPNEGO_OID_LEN 7 78#define SPNEGO_OID_LEN 7
79#define NTLMSSP_OID_LEN 10 79#define NTLMSSP_OID_LEN 10
80#define KRB5_OID_LEN 7
81#define MSKRB5_OID_LEN 7
80static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; 82static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
81static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; 83static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
84static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 };
85static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 };
82 86
83/* 87/*
84 * ASN.1 context. 88 * ASN.1 context.
@@ -457,6 +461,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
457 unsigned long *oid = NULL; 461 unsigned long *oid = NULL;
458 unsigned int cls, con, tag, oidlen, rc; 462 unsigned int cls, con, tag, oidlen, rc;
459 int use_ntlmssp = FALSE; 463 int use_ntlmssp = FALSE;
464 int use_kerberos = FALSE;
460 465
461 *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/ 466 *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/
462 467
@@ -545,18 +550,28 @@ decode_negTokenInit(unsigned char *security_blob, int length,
545 return 0; 550 return 0;
546 } 551 }
547 if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { 552 if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
548 rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); 553 if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
549 if (rc) { 554
550 cFYI(1, 555 cFYI(1,
551 ("OID len = %d oid = 0x%lx 0x%lx " 556 ("OID len = %d oid = 0x%lx 0x%lx "
552 "0x%lx 0x%lx", 557 "0x%lx 0x%lx",
553 oidlen, *oid, *(oid + 1), 558 oidlen, *oid, *(oid + 1),
554 *(oid + 2), *(oid + 3))); 559 *(oid + 2), *(oid + 3)));
555 rc = compare_oid(oid, oidlen, 560
556 NTLMSSP_OID, NTLMSSP_OID_LEN); 561 if (compare_oid(oid, oidlen,
557 kfree(oid); 562 MSKRB5_OID,
558 if (rc) 563 MSKRB5_OID_LEN))
564 use_kerberos = TRUE;
565 else if (compare_oid(oid, oidlen,
566 KRB5_OID,
567 KRB5_OID_LEN))
568 use_kerberos = TRUE;
569 else if (compare_oid(oid, oidlen,
570 NTLMSSP_OID,
571 NTLMSSP_OID_LEN))
559 use_ntlmssp = TRUE; 572 use_ntlmssp = TRUE;
573
574 kfree(oid);
560 } 575 }
561 } else { 576 } else {
562 cFYI(1, ("Should be an oid what is going on?")); 577 cFYI(1, ("Should be an oid what is going on?"));
@@ -609,12 +624,10 @@ decode_negTokenInit(unsigned char *security_blob, int length,
609 ctx.pointer)); /* is this UTF-8 or ASCII? */ 624 ctx.pointer)); /* is this UTF-8 or ASCII? */
610 } 625 }
611 626
612 /* if (use_kerberos) 627 if (use_kerberos)
613 *secType = Kerberos 628 *secType = Kerberos;
614 else */ 629 else if (use_ntlmssp)
615 if (use_ntlmssp) {
616 *secType = NTLMSSP; 630 *secType = NTLMSSP;
617 }
618 631
619 return 1; 632 return 1;
620} 633}
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
new file mode 100644
index 000000000000..ad54a3a6e434
--- /dev/null
+++ b/fs/cifs/cifs_spnego.c
@@ -0,0 +1,128 @@
1/*
2 * fs/cifs/cifs_spnego.c -- SPNEGO upcall management for CIFS
3 *
4 * Copyright (c) 2007 Red Hat, Inc.
5 * Author(s): Jeff Layton (jlayton@redhat.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <linux/list.h>
23#include <linux/string.h>
24#include <keys/user-type.h>
25#include <linux/key-type.h>
26#include "cifsglob.h"
27#include "cifs_spnego.h"
28#include "cifs_debug.h"
29
30/* create a new cifs key */
31static int
32cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen)
33{
34 char *payload;
35 int ret;
36
37 ret = -ENOMEM;
38 payload = kmalloc(datalen, GFP_KERNEL);
39 if (!payload)
40 goto error;
41
42 /* attach the data */
43 memcpy(payload, data, datalen);
44 rcu_assign_pointer(key->payload.data, payload);
45 ret = 0;
46
47error:
48 return ret;
49}
50
51static void
52cifs_spnego_key_destroy(struct key *key)
53{
54 kfree(key->payload.data);
55}
56
57
58/*
59 * keytype for CIFS spnego keys
60 */
61struct key_type cifs_spnego_key_type = {
62 .name = "cifs.spnego",
63 .instantiate = cifs_spnego_key_instantiate,
64 .match = user_match,
65 .destroy = cifs_spnego_key_destroy,
66 .describe = user_describe,
67};
68
69/* get a key struct with a SPNEGO security blob, suitable for session setup */
70struct key *
71cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname)
72{
73 struct TCP_Server_Info *server = sesInfo->server;
74 char *description, *dp;
75 size_t desc_len;
76 struct key *spnego_key;
77
78
79 /* version + ;ip{4|6}= + address + ;host=hostname +
80 ;sec= + ;uid= + NULL */
81 desc_len = 4 + 5 + 32 + 1 + 5 + strlen(hostname) +
82 strlen(";sec=krb5") + 7 + sizeof(uid_t)*2 + 1;
83 spnego_key = ERR_PTR(-ENOMEM);
84 description = kzalloc(desc_len, GFP_KERNEL);
85 if (description == NULL)
86 goto out;
87
88 dp = description;
89 /* start with version and hostname portion of UNC string */
90 spnego_key = ERR_PTR(-EINVAL);
91 sprintf(dp, "0x%2.2x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
92 hostname);
93 dp = description + strlen(description);
94
95 /* add the server address */
96 if (server->addr.sockAddr.sin_family == AF_INET)
97 sprintf(dp, "ip4=" NIPQUAD_FMT,
98 NIPQUAD(server->addr.sockAddr.sin_addr));
99 else if (server->addr.sockAddr.sin_family == AF_INET6)
100 sprintf(dp, "ip6=" NIP6_SEQFMT,
101 NIP6(server->addr.sockAddr6.sin6_addr));
102 else
103 goto out;
104
105 dp = description + strlen(description);
106
107 /* for now, only sec=krb5 is valid */
108 if (server->secType == Kerberos)
109 sprintf(dp, ";sec=krb5");
110 else
111 goto out;
112
113 dp = description + strlen(description);
114 sprintf(dp, ";uid=0x%x", sesInfo->linux_uid);
115
116 cFYI(1, ("key description = %s", description));
117 spnego_key = request_key(&cifs_spnego_key_type, description, "");
118
119 if (cifsFYI && !IS_ERR(spnego_key)) {
120 struct cifs_spnego_msg *msg = spnego_key->payload.data;
121 cifs_dump_mem("SPNEGO reply blob:", msg->data,
122 msg->secblob_len + msg->sesskey_len);
123 }
124
125out:
126 kfree(description);
127 return spnego_key;
128}
diff --git a/fs/cifs/cifs_spnego.h b/fs/cifs/cifs_spnego.h
new file mode 100644
index 000000000000..f443f3b35134
--- /dev/null
+++ b/fs/cifs/cifs_spnego.h
@@ -0,0 +1,46 @@
1/*
2 * fs/cifs/cifs_spnego.h -- SPNEGO upcall management for CIFS
3 *
4 * Copyright (c) 2007 Red Hat, Inc.
5 * Author(s): Jeff Layton (jlayton@redhat.com)
6 * 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 _CIFS_SPNEGO_H
24#define _CIFS_SPNEGO_H
25
26#define CIFS_SPNEGO_UPCALL_VERSION 1
27
28/*
29 * The version field should always be set to CIFS_SPNEGO_UPCALL_VERSION.
30 * The flags field is for future use. The request-key callout should set
31 * sesskey_len and secblob_len, and then concatenate the SessKey+SecBlob
32 * and stuff it in the data field.
33 */
34struct cifs_spnego_msg {
35 uint32_t version;
36 uint32_t flags;
37 uint32_t sesskey_len;
38 uint32_t secblob_len;
39 uint8_t data[1];
40};
41
42#ifdef __KERNEL__
43extern struct key_type cifs_spnego_key_type;
44#endif /* KERNEL */
45
46#endif /* _CIFS_SPNEGO_H */
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index e8e56353f5a1..dabbce00712b 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -38,13 +38,13 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
38 {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, 38 {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
39 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(544), 0, 0, 0} }, "root"}, 39 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(544), 0, 0, 0} }, "root"},
40 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(545), 0, 0, 0} }, "users"}, 40 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(545), 0, 0, 0} }, "users"},
41 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} 41 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} }
42}; 42;
43 43
44 44
45/* security id for everyone */ 45/* security id for everyone */
46static const struct cifs_sid sid_everyone = 46static const struct cifs_sid sid_everyone = {
47 {1, 1, {0, 0, 0, 0, 0, 0}, {} }; 47 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
48/* group users */ 48/* group users */
49static const struct cifs_sid sid_user = 49static const struct cifs_sid sid_user =
50 {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; 50 {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
@@ -97,7 +97,7 @@ int match_sid(struct cifs_sid *ctsid)
97 97
98/* if the two SIDs (roughly equivalent to a UUID for a user or group) are 98/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
99 the same returns 1, if they do not match returns 0 */ 99 the same returns 1, if they do not match returns 0 */
100int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) 100int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
101{ 101{
102 int i; 102 int i;
103 int num_subauth, num_sat, num_saw; 103 int num_subauth, num_sat, num_saw;
@@ -129,66 +129,142 @@ int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid)
129 return (1); /* sids compare/match */ 129 return (1); /* sids compare/match */
130} 130}
131 131
132/*
133 change posix mode to reflect permissions
134 pmode is the existing mode (we only want to overwrite part of this
135 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
136*/
137static void access_flags_to_mode(__u32 ace_flags, int type, umode_t *pmode,
138 umode_t *pbits_to_set)
139{
140 /* the order of ACEs is important. The canonical order is to begin with
141 DENY entries followed by ALLOW, otherwise an allow entry could be
142 encountered first, making the subsequent deny entry like "dead code"
143 which would be superflous since Windows stops when a match is made
144 for the operation you are trying to perform for your user */
145
146 /* For deny ACEs we change the mask so that subsequent allow access
147 control entries do not turn on the bits we are denying */
148 if (type == ACCESS_DENIED) {
149 if (ace_flags & GENERIC_ALL) {
150 *pbits_to_set &= ~S_IRWXUGO;
151 }
152 if ((ace_flags & GENERIC_WRITE) ||
153 ((ace_flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
154 *pbits_to_set &= ~S_IWUGO;
155 if ((ace_flags & GENERIC_READ) ||
156 ((ace_flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
157 *pbits_to_set &= ~S_IRUGO;
158 if ((ace_flags & GENERIC_EXECUTE) ||
159 ((ace_flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
160 *pbits_to_set &= ~S_IXUGO;
161 return;
162 } else if (type != ACCESS_ALLOWED) {
163 cERROR(1, ("unknown access control type %d", type));
164 return;
165 }
166 /* else ACCESS_ALLOWED type */
167
168 if (ace_flags & GENERIC_ALL) {
169 *pmode |= (S_IRWXUGO & (*pbits_to_set));
170#ifdef CONFIG_CIFS_DEBUG2
171 cFYI(1, ("all perms"));
172#endif
173 return;
174 }
175 if ((ace_flags & GENERIC_WRITE) ||
176 ((ace_flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
177 *pmode |= (S_IWUGO & (*pbits_to_set));
178 if ((ace_flags & GENERIC_READ) ||
179 ((ace_flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
180 *pmode |= (S_IRUGO & (*pbits_to_set));
181 if ((ace_flags & GENERIC_EXECUTE) ||
182 ((ace_flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
183 *pmode |= (S_IXUGO & (*pbits_to_set));
184
185#ifdef CONFIG_CIFS_DEBUG2
186 cFYI(1, ("access flags 0x%x mode now 0x%x", ace_flags, *pmode));
187#endif
188 return;
189}
190
191/*
192 Generate access flags to reflect permissions mode is the existing mode.
193 This function is called for every ACE in the DACL whose SID matches
194 with either owner or group or everyone.
195*/
196
197static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
198 __u32 *pace_flags)
199{
200 /* reset access mask */
201 *pace_flags = 0x0;
202
203 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
204 mode &= bits_to_use;
205
206 /* check for R/W/X UGO since we do not know whose flags
207 is this but we have cleared all the bits sans RWX for
208 either user or group or other as per bits_to_use */
209 if (mode & S_IRUGO)
210 *pace_flags |= SET_FILE_READ_RIGHTS;
211 if (mode & S_IWUGO)
212 *pace_flags |= SET_FILE_WRITE_RIGHTS;
213 if (mode & S_IXUGO)
214 *pace_flags |= SET_FILE_EXEC_RIGHTS;
215
216#ifdef CONFIG_CIFS_DEBUG2
217 cFYI(1, ("mode: 0x%x, access flags now 0x%x", mode, *pace_flags));
218#endif
219 return;
220}
221
132 222
133static void parse_ace(struct cifs_ace *pace, char *end_of_acl) 223#ifdef CONFIG_CIFS_DEBUG2
224static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
134{ 225{
135 int num_subauth; 226 int num_subauth;
136 227
137 /* validate that we do not go past end of acl */ 228 /* validate that we do not go past end of acl */
138 229
139 /* XXX this if statement can be removed 230 if (le16_to_cpu(pace->size) < 16) {
140 if (end_of_acl < (char *)pace + sizeof(struct cifs_ace)) { 231 cERROR(1, ("ACE too small, %d", le16_to_cpu(pace->size)));
232 return;
233 }
234
235 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
141 cERROR(1, ("ACL too small to parse ACE")); 236 cERROR(1, ("ACL too small to parse ACE"));
142 return; 237 return;
143 } */ 238 }
144 239
145 num_subauth = pace->num_subauth; 240 num_subauth = pace->sid.num_subauth;
146 if (num_subauth) { 241 if (num_subauth) {
147#ifdef CONFIG_CIFS_DEBUG2
148 int i; 242 int i;
149 cFYI(1, ("ACE revision %d num_subauth %d", 243 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
150 pace->revision, pace->num_subauth)); 244 pace->sid.revision, pace->sid.num_subauth, pace->type,
245 pace->flags, pace->size));
151 for (i = 0; i < num_subauth; ++i) { 246 for (i = 0; i < num_subauth; ++i) {
152 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, 247 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
153 le32_to_cpu(pace->sub_auth[i]))); 248 le32_to_cpu(pace->sid.sub_auth[i])));
154 } 249 }
155 250
156 /* BB add length check to make sure that we do not have huge 251 /* BB add length check to make sure that we do not have huge
157 num auths and therefore go off the end */ 252 num auths and therefore go off the end */
158
159 cFYI(1, ("RID %d", le32_to_cpu(pace->sub_auth[num_subauth-1])));
160#endif
161 } 253 }
162 254
163 return; 255 return;
164} 256}
165
166static void parse_ntace(struct cifs_ntace *pntace, char *end_of_acl)
167{
168 /* validate that we do not go past end of acl */
169 if (end_of_acl < (char *)pntace + sizeof(struct cifs_ntace)) {
170 cERROR(1, ("ACL too small to parse NT ACE"));
171 return;
172 }
173
174#ifdef CONFIG_CIFS_DEBUG2
175 cFYI(1, ("NTACE type %d flags 0x%x size %d, access Req 0x%x",
176 pntace->type, pntace->flags, pntace->size,
177 pntace->access_req));
178#endif 257#endif
179 return;
180}
181
182 258
183 259
184static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, 260static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
185 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid) 261 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
262 struct inode *inode)
186{ 263{
187 int i; 264 int i;
188 int num_aces = 0; 265 int num_aces = 0;
189 int acl_size; 266 int acl_size;
190 char *acl_base; 267 char *acl_base;
191 struct cifs_ntace **ppntace;
192 struct cifs_ace **ppace; 268 struct cifs_ace **ppace;
193 269
194 /* BB need to add parm so we can store the SID BB */ 270 /* BB need to add parm so we can store the SID BB */
@@ -205,50 +281,63 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
205 le32_to_cpu(pdacl->num_aces))); 281 le32_to_cpu(pdacl->num_aces)));
206#endif 282#endif
207 283
284 /* reset rwx permissions for user/group/other.
285 Also, if num_aces is 0 i.e. DACL has no ACEs,
286 user/group/other have no permissions */
287 inode->i_mode &= ~(S_IRWXUGO);
288
289 if (!pdacl) {
290 /* no DACL in the security descriptor, set
291 all the permissions for user/group/other */
292 inode->i_mode |= S_IRWXUGO;
293 return;
294 }
208 acl_base = (char *)pdacl; 295 acl_base = (char *)pdacl;
209 acl_size = sizeof(struct cifs_acl); 296 acl_size = sizeof(struct cifs_acl);
210 297
211 num_aces = le32_to_cpu(pdacl->num_aces); 298 num_aces = le32_to_cpu(pdacl->num_aces);
212 if (num_aces > 0) { 299 if (num_aces > 0) {
213 ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), 300 umode_t user_mask = S_IRWXU;
214 GFP_KERNEL); 301 umode_t group_mask = S_IRWXG;
302 umode_t other_mask = S_IRWXO;
303
215 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), 304 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
216 GFP_KERNEL); 305 GFP_KERNEL);
217 306
218/* cifscred->cecount = pdacl->num_aces; 307/* cifscred->cecount = pdacl->num_aces;
219 cifscred->ntaces = kmalloc(num_aces *
220 sizeof(struct cifs_ntace *), GFP_KERNEL);
221 cifscred->aces = kmalloc(num_aces * 308 cifscred->aces = kmalloc(num_aces *
222 sizeof(struct cifs_ace *), GFP_KERNEL);*/ 309 sizeof(struct cifs_ace *), GFP_KERNEL);*/
223 310
224 for (i = 0; i < num_aces; ++i) { 311 for (i = 0; i < num_aces; ++i) {
225 ppntace[i] = (struct cifs_ntace *) 312 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
226 (acl_base + acl_size); 313#ifdef CONFIG_CIFS_DEBUG2
227 ppace[i] = (struct cifs_ace *) ((char *)ppntace[i] + 314 dump_ace(ppace[i], end_of_acl);
228 sizeof(struct cifs_ntace)); 315#endif
229 316 if (compare_sids(&(ppace[i]->sid), pownersid))
230 parse_ntace(ppntace[i], end_of_acl); 317 access_flags_to_mode(ppace[i]->access_req,
231 if (end_of_acl < ((char *)ppace[i] + 318 ppace[i]->type,
232 (le16_to_cpu(ppntace[i]->size) - 319 &(inode->i_mode),
233 sizeof(struct cifs_ntace)))) { 320 &user_mask);
234 cERROR(1, ("ACL too small to parse ACE")); 321 if (compare_sids(&(ppace[i]->sid), pgrpsid))
235 break; 322 access_flags_to_mode(ppace[i]->access_req,
236 } else 323 ppace[i]->type,
237 parse_ace(ppace[i], end_of_acl); 324 &(inode->i_mode),
238 325 &group_mask);
239/* memcpy((void *)(&(cifscred->ntaces[i])), 326 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
240 (void *)ppntace[i], 327 access_flags_to_mode(ppace[i]->access_req,
241 sizeof(struct cifs_ntace)); 328 ppace[i]->type,
242 memcpy((void *)(&(cifscred->aces[i])), 329 &(inode->i_mode),
330 &other_mask);
331
332/* memcpy((void *)(&(cifscred->aces[i])),
243 (void *)ppace[i], 333 (void *)ppace[i],
244 sizeof(struct cifs_ace)); */ 334 sizeof(struct cifs_ace)); */
245 335
246 acl_base = (char *)ppntace[i]; 336 acl_base = (char *)ppace[i];
247 acl_size = le16_to_cpu(ppntace[i]->size); 337 acl_size = le16_to_cpu(ppace[i]->size);
248 } 338 }
249 339
250 kfree(ppace); 340 kfree(ppace);
251 kfree(ppntace);
252 } 341 }
253 342
254 return; 343 return;
@@ -257,20 +346,20 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
257 346
258static int parse_sid(struct cifs_sid *psid, char *end_of_acl) 347static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
259{ 348{
260
261 /* BB need to add parm so we can store the SID BB */ 349 /* BB need to add parm so we can store the SID BB */
262 350
263 /* validate that we do not go past end of acl */ 351 /* validate that we do not go past end of ACL - sid must be at least 8
264 if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) { 352 bytes long (assuming no sub-auths - e.g. the null SID */
265 cERROR(1, ("ACL too small to parse SID")); 353 if (end_of_acl < (char *)psid + 8) {
354 cERROR(1, ("ACL too small to parse SID %p", psid));
266 return -EINVAL; 355 return -EINVAL;
267 } 356 }
268 357
269 if (psid->num_subauth) { 358 if (psid->num_subauth) {
270#ifdef CONFIG_CIFS_DEBUG2 359#ifdef CONFIG_CIFS_DEBUG2
271 int i; 360 int i;
272 cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x", 361 cFYI(1, ("SID revision %d num_auth %d",
273 psid->revision, psid->num_subauth, psid->sub_auth[0])); 362 psid->revision, psid->num_subauth));
274 363
275 for (i = 0; i < psid->num_subauth; i++) { 364 for (i = 0; i < psid->num_subauth; i++) {
276 cFYI(1, ("SID sub_auth[%d]: 0x%x ", i, 365 cFYI(1, ("SID sub_auth[%d]: 0x%x ", i,
@@ -289,27 +378,32 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
289 378
290 379
291/* Convert CIFS ACL to POSIX form */ 380/* Convert CIFS ACL to POSIX form */
292int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) 381static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
382 struct inode *inode)
293{ 383{
294 int rc; 384 int rc;
295 struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 385 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
296 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ 386 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
297 char *end_of_acl = ((char *)pntsd) + acl_len; 387 char *end_of_acl = ((char *)pntsd) + acl_len;
388 __u32 dacloffset;
389
390 if ((inode == NULL) || (pntsd == NULL))
391 return -EIO;
298 392
299 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 393 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
300 le32_to_cpu(pntsd->osidoffset)); 394 le32_to_cpu(pntsd->osidoffset));
301 group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 395 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
302 le32_to_cpu(pntsd->gsidoffset)); 396 le32_to_cpu(pntsd->gsidoffset));
303 dacl_ptr = (struct cifs_acl *)((char *)pntsd + 397 dacloffset = le32_to_cpu(pntsd->dacloffset);
304 le32_to_cpu(pntsd->dacloffset)); 398 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
305#ifdef CONFIG_CIFS_DEBUG2 399#ifdef CONFIG_CIFS_DEBUG2
306 cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x " 400 cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
307 "sacloffset 0x%x dacloffset 0x%x", 401 "sacloffset 0x%x dacloffset 0x%x",
308 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), 402 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
309 le32_to_cpu(pntsd->gsidoffset), 403 le32_to_cpu(pntsd->gsidoffset),
310 le32_to_cpu(pntsd->sacloffset), 404 le32_to_cpu(pntsd->sacloffset), dacloffset));
311 le32_to_cpu(pntsd->dacloffset)));
312#endif 405#endif
406/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
313 rc = parse_sid(owner_sid_ptr, end_of_acl); 407 rc = parse_sid(owner_sid_ptr, end_of_acl);
314 if (rc) 408 if (rc)
315 return rc; 409 return rc;
@@ -318,16 +412,120 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
318 if (rc) 412 if (rc)
319 return rc; 413 return rc;
320 414
321 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr); 415 if (dacloffset)
416 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
417 group_sid_ptr, inode);
418 else
419 cFYI(1, ("no ACL")); /* BB grant all or default perms? */
322 420
323/* cifscred->uid = owner_sid_ptr->rid; 421/* cifscred->uid = owner_sid_ptr->rid;
324 cifscred->gid = group_sid_ptr->rid; 422 cifscred->gid = group_sid_ptr->rid;
325 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr, 423 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
326 sizeof (struct cifs_sid)); 424 sizeof(struct cifs_sid));
327 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, 425 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
328 sizeof (struct cifs_sid)); */ 426 sizeof(struct cifs_sid)); */
329 427
330 428
331 return (0); 429 return (0);
332} 430}
431
432
433/* Retrieve an ACL from the server */
434static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
435 const char *path)
436{
437 struct cifsFileInfo *open_file;
438 int unlock_file = FALSE;
439 int xid;
440 int rc = -EIO;
441 __u16 fid;
442 struct super_block *sb;
443 struct cifs_sb_info *cifs_sb;
444 struct cifs_ntsd *pntsd = NULL;
445
446 cFYI(1, ("get mode from ACL for %s", path));
447
448 if (inode == NULL)
449 return NULL;
450
451 xid = GetXid();
452 open_file = find_readable_file(CIFS_I(inode));
453 sb = inode->i_sb;
454 if (sb == NULL) {
455 FreeXid(xid);
456 return NULL;
457 }
458 cifs_sb = CIFS_SB(sb);
459
460 if (open_file) {
461 unlock_file = TRUE;
462 fid = open_file->netfid;
463 } else {
464 int oplock = FALSE;
465 /* open file */
466 rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
467 READ_CONTROL, 0, &fid, &oplock, NULL,
468 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
469 CIFS_MOUNT_MAP_SPECIAL_CHR);
470 if (rc != 0) {
471 cERROR(1, ("Unable to open file to get ACL"));
472 FreeXid(xid);
473 return NULL;
474 }
475 }
476
477 rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
478 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
479 if (unlock_file == TRUE)
480 atomic_dec(&open_file->wrtPending);
481 else
482 CIFSSMBClose(xid, cifs_sb->tcon, fid);
483
484 FreeXid(xid);
485 return pntsd;
486}
487
488/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
489void acl_to_uid_mode(struct inode *inode, const char *path)
490{
491 struct cifs_ntsd *pntsd = NULL;
492 u32 acllen = 0;
493 int rc = 0;
494
495#ifdef CONFIG_CIFS_DEBUG2
496 cFYI(1, ("converting ACL to mode for %s", path));
497#endif
498 pntsd = get_cifs_acl(&acllen, inode, path);
499
500 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
501 if (pntsd)
502 rc = parse_sec_desc(pntsd, acllen, inode);
503 if (rc)
504 cFYI(1, ("parse sec desc failed rc = %d", rc));
505
506 kfree(pntsd);
507 return;
508}
509
510/* Convert mode bits to an ACL so we can update the ACL on the server */
511int mode_to_acl(struct inode *inode, const char *path)
512{
513 int rc = 0;
514 __u32 acllen = 0;
515 struct cifs_ntsd *pntsd = NULL;
516
517 cFYI(1, ("set ACL from mode for %s", path));
518
519 /* Get the security descriptor */
520 pntsd = get_cifs_acl(&acllen, inode, path);
521
522 /* Add/Modify the three ACEs for owner, group, everyone
523 while retaining the other ACEs */
524
525 /* Set the security descriptor */
526
527
528 kfree(pntsd);
529 return rc;
530}
333#endif /* CONFIG_CIFS_EXPERIMENTAL */ 531#endif /* CONFIG_CIFS_EXPERIMENTAL */
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
index 420f87813647..93a7c3462ea2 100644
--- a/fs/cifs/cifsacl.h
+++ b/fs/cifs/cifsacl.h
@@ -35,6 +35,9 @@
35#define UBITSHIFT 6 35#define UBITSHIFT 6
36#define GBITSHIFT 3 36#define GBITSHIFT 3
37 37
38#define ACCESS_ALLOWED 0
39#define ACCESS_DENIED 1
40
38struct cifs_ntsd { 41struct cifs_ntsd {
39 __le16 revision; /* revision level */ 42 __le16 revision; /* revision level */
40 __le16 type; 43 __le16 type;
@@ -48,7 +51,7 @@ struct cifs_sid {
48 __u8 revision; /* revision level */ 51 __u8 revision; /* revision level */
49 __u8 num_subauth; 52 __u8 num_subauth;
50 __u8 authority[6]; 53 __u8 authority[6];
51 __le32 sub_auth[5]; /* sub_auth[num_subauth] */ /* BB FIXME endianness BB */ 54 __le32 sub_auth[5]; /* sub_auth[num_subauth] */
52} __attribute__((packed)); 55} __attribute__((packed));
53 56
54struct cifs_acl { 57struct cifs_acl {
@@ -57,18 +60,12 @@ struct cifs_acl {
57 __le32 num_aces; 60 __le32 num_aces;
58} __attribute__((packed)); 61} __attribute__((packed));
59 62
60struct cifs_ntace { /* first part of ACE which contains perms */ 63struct cifs_ace {
61 __u8 type; 64 __u8 type;
62 __u8 flags; 65 __u8 flags;
63 __le16 size; 66 __le16 size;
64 __le32 access_req; 67 __le32 access_req;
65} __attribute__((packed)); 68 struct cifs_sid sid; /* ie UUID of user or group who gets these perms */
66
67struct cifs_ace { /* last part of ACE which includes user info */
68 __u8 revision; /* revision level */
69 __u8 num_subauth;
70 __u8 authority[6];
71 __le32 sub_auth[5];
72} __attribute__((packed)); 69} __attribute__((packed));
73 70
74struct cifs_wksid { 71struct cifs_wksid {
@@ -79,7 +76,7 @@ struct cifs_wksid {
79#ifdef CONFIG_CIFS_EXPERIMENTAL 76#ifdef CONFIG_CIFS_EXPERIMENTAL
80 77
81extern int match_sid(struct cifs_sid *); 78extern int match_sid(struct cifs_sid *);
82extern int compare_sids(struct cifs_sid *, struct cifs_sid *); 79extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *);
83 80
84#endif /* CONFIG_CIFS_EXPERIMENTAL */ 81#endif /* CONFIG_CIFS_EXPERIMENTAL */
85 82
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 632070b4275d..4ff8939c6cc7 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -99,15 +99,16 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
99 MD5Init(&context); 99 MD5Init(&context);
100 MD5Update(&context, (char *)&key->data, key->len); 100 MD5Update(&context, (char *)&key->data, key->len);
101 for (i = 0; i < n_vec; i++) { 101 for (i = 0; i < n_vec; i++) {
102 if (iov[i].iov_len == 0)
103 continue;
102 if (iov[i].iov_base == NULL) { 104 if (iov[i].iov_base == NULL) {
103 cERROR(1, ("null iovec entry")); 105 cERROR(1, ("null iovec entry"));
104 return -EIO; 106 return -EIO;
105 } else if (iov[i].iov_len == 0) 107 }
106 break; /* bail out if we are sent nothing to sign */
107 /* The first entry includes a length field (which does not get 108 /* The first entry includes a length field (which does not get
108 signed that occupies the first 4 bytes before the header */ 109 signed that occupies the first 4 bytes before the header */
109 if (i == 0) { 110 if (i == 0) {
110 if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */ 111 if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
111 break; /* nothing to sign or corrupt header */ 112 break; /* nothing to sign or corrupt header */
112 MD5Update(&context, iov[0].iov_base+4, 113 MD5Update(&context, iov[0].iov_base+4,
113 iov[0].iov_len-4); 114 iov[0].iov_len-4);
@@ -122,7 +123,7 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
122 123
123 124
124int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, 125int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
125 __u32 * pexpected_response_sequence_number) 126 __u32 *pexpected_response_sequence_number)
126{ 127{
127 int rc = 0; 128 int rc = 0;
128 char smb_signature[20]; 129 char smb_signature[20];
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index a6fbea57c4b1..416dc9fe8961 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -43,6 +43,8 @@
43#include "cifs_debug.h" 43#include "cifs_debug.h"
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>
47#include "cifs_spnego.h"
46#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ 48#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
47 49
48#ifdef CONFIG_CIFS_QUOTA 50#ifdef CONFIG_CIFS_QUOTA
@@ -1005,12 +1007,16 @@ init_cifs(void)
1005 rc = register_filesystem(&cifs_fs_type); 1007 rc = register_filesystem(&cifs_fs_type);
1006 if (rc) 1008 if (rc)
1007 goto out_destroy_request_bufs; 1009 goto out_destroy_request_bufs;
1008 1010#ifdef CONFIG_CIFS_UPCALL
1011 rc = register_key_type(&cifs_spnego_key_type);
1012 if (rc)
1013 goto out_unregister_filesystem;
1014#endif
1009 oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd"); 1015 oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
1010 if (IS_ERR(oplockThread)) { 1016 if (IS_ERR(oplockThread)) {
1011 rc = PTR_ERR(oplockThread); 1017 rc = PTR_ERR(oplockThread);
1012 cERROR(1, ("error %d create oplock thread", rc)); 1018 cERROR(1, ("error %d create oplock thread", rc));
1013 goto out_unregister_filesystem; 1019 goto out_unregister_key_type;
1014 } 1020 }
1015 1021
1016 dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd"); 1022 dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
@@ -1024,7 +1030,11 @@ init_cifs(void)
1024 1030
1025 out_stop_oplock_thread: 1031 out_stop_oplock_thread:
1026 kthread_stop(oplockThread); 1032 kthread_stop(oplockThread);
1033 out_unregister_key_type:
1034#ifdef CONFIG_CIFS_UPCALL
1035 unregister_key_type(&cifs_spnego_key_type);
1027 out_unregister_filesystem: 1036 out_unregister_filesystem:
1037#endif
1028 unregister_filesystem(&cifs_fs_type); 1038 unregister_filesystem(&cifs_fs_type);
1029 out_destroy_request_bufs: 1039 out_destroy_request_bufs:
1030 cifs_destroy_request_bufs(); 1040 cifs_destroy_request_bufs();
@@ -1046,6 +1056,9 @@ exit_cifs(void)
1046#ifdef CONFIG_PROC_FS 1056#ifdef CONFIG_PROC_FS
1047 cifs_proc_clean(); 1057 cifs_proc_clean();
1048#endif 1058#endif
1059#ifdef CONFIG_CIFS_UPCALL
1060 unregister_key_type(&cifs_spnego_key_type);
1061#endif
1049 unregister_filesystem(&cifs_fs_type); 1062 unregister_filesystem(&cifs_fs_type);
1050 cifs_destroy_inodecache(); 1063 cifs_destroy_inodecache();
1051 cifs_destroy_mids(); 1064 cifs_destroy_mids();
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 5574ba3ab1f9..2a21dc66f0de 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -106,5 +106,5 @@ extern int cifs_ioctl(struct inode *inode, struct file *filep,
106extern const struct export_operations cifs_export_ops; 106extern const struct export_operations cifs_export_ops;
107#endif /* EXPERIMENTAL */ 107#endif /* EXPERIMENTAL */
108 108
109#define CIFS_VERSION "1.51" 109#define CIFS_VERSION "1.52"
110#endif /* _CIFSFS_H */ 110#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index c41ff74e9128..dbe6b846f37f 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -220,6 +220,23 @@
220 | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) 220 | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES)
221#define FILE_EXEC_RIGHTS (FILE_EXECUTE) 221#define FILE_EXEC_RIGHTS (FILE_EXECUTE)
222 222
223#define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_WRITE_EA \
224 | FILE_READ_ATTRIBUTES \
225 | FILE_WRITE_ATTRIBUTES \
226 | DELETE | READ_CONTROL | WRITE_DAC \
227 | WRITE_OWNER | SYNCHRONIZE)
228#define SET_FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \
229 | FILE_READ_EA | FILE_WRITE_EA \
230 | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES \
231 | FILE_WRITE_ATTRIBUTES \
232 | DELETE | READ_CONTROL | WRITE_DAC \
233 | WRITE_OWNER | SYNCHRONIZE)
234#define SET_FILE_EXEC_RIGHTS (FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE \
235 | FILE_READ_ATTRIBUTES \
236 | FILE_WRITE_ATTRIBUTES \
237 | DELETE | READ_CONTROL | WRITE_DAC \
238 | WRITE_OWNER | SYNCHRONIZE)
239
223 240
224/* 241/*
225 * Invalid readdir handle 242 * Invalid readdir handle
@@ -1211,6 +1228,29 @@ typedef struct smb_com_transaction_qsec_req {
1211 __le32 AclFlags; 1228 __le32 AclFlags;
1212} __attribute__((packed)) QUERY_SEC_DESC_REQ; 1229} __attribute__((packed)) QUERY_SEC_DESC_REQ;
1213 1230
1231
1232typedef struct smb_com_transaction_ssec_req {
1233 struct smb_hdr hdr; /* wct = 19 */
1234 __u8 MaxSetupCount;
1235 __u16 Reserved;
1236 __le32 TotalParameterCount;
1237 __le32 TotalDataCount;
1238 __le32 MaxParameterCount;
1239 __le32 MaxDataCount;
1240 __le32 ParameterCount;
1241 __le32 ParameterOffset;
1242 __le32 DataCount;
1243 __le32 DataOffset;
1244 __u8 SetupCount; /* no setup words follow subcommand */
1245 /* SNIA spec incorrectly included spurious pad here */
1246 __le16 SubCommand; /* 3 = SET_SECURITY_DESC */
1247 __le16 ByteCount; /* bcc = 3 + 8 */
1248 __u8 Pad[3];
1249 __u16 Fid;
1250 __u16 Reserved2;
1251 __le32 AclFlags;
1252} __attribute__((packed)) SET_SEC_DESC_REQ;
1253
1214typedef struct smb_com_transaction_change_notify_req { 1254typedef struct smb_com_transaction_change_notify_req {
1215 struct smb_hdr hdr; /* wct = 23 */ 1255 struct smb_hdr hdr; /* wct = 23 */
1216 __u8 MaxSetupCount; 1256 __u8 MaxSetupCount;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 1a883663b22d..dd1d7c200ee6 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -61,6 +61,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
61extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); 61extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
62extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); 62extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
63extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); 63extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
64#ifdef CONFIG_CIFS_EXPERIMENTAL
65extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
66#endif
64extern unsigned int smbCalcSize(struct smb_hdr *ptr); 67extern unsigned int smbCalcSize(struct smb_hdr *ptr);
65extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); 68extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
66extern int decode_negTokenInit(unsigned char *security_blob, int length, 69extern int decode_negTokenInit(unsigned char *security_blob, int length,
@@ -73,6 +76,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
73extern int small_smb_init_no_tc(const int smb_cmd, const int wct, 76extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
74 struct cifsSesInfo *ses, 77 struct cifsSesInfo *ses,
75 void **request_buf); 78 void **request_buf);
79extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo,
80 const char *hostname);
76extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, 81extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
77 const int stage, 82 const int stage,
78 const struct nls_table *nls_cp); 83 const struct nls_table *nls_cp);
@@ -92,6 +97,8 @@ extern int cifs_get_inode_info(struct inode **pinode,
92extern int cifs_get_inode_info_unix(struct inode **pinode, 97extern int cifs_get_inode_info_unix(struct inode **pinode,
93 const unsigned char *search_path, 98 const unsigned char *search_path,
94 struct super_block *sb, int xid); 99 struct super_block *sb, int xid);
100extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
101extern int mode_to_acl(struct inode *inode, const char *path);
95 102
96extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, 103extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
97 const char *); 104 const char *);
@@ -311,7 +318,6 @@ extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
311#ifdef CONFIG_CIFS_WEAK_PW_HASH 318#ifdef CONFIG_CIFS_WEAK_PW_HASH
312extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key); 319extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
313#endif /* CIFS_WEAK_PW_HASH */ 320#endif /* CIFS_WEAK_PW_HASH */
314extern int parse_sec_desc(struct cifs_ntsd *, int);
315extern int CIFSSMBCopy(int xid, 321extern int CIFSSMBCopy(int xid,
316 struct cifsTconInfo *source_tcon, 322 struct cifsTconInfo *source_tcon,
317 const char *fromName, 323 const char *fromName,
@@ -336,8 +342,7 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
336 const void *ea_value, const __u16 ea_value_len, 342 const void *ea_value, const __u16 ea_value_len,
337 const struct nls_table *nls_codepage, int remap_special_chars); 343 const struct nls_table *nls_codepage, int remap_special_chars);
338extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, 344extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
339 __u16 fid, char *acl_inf, const int buflen, 345 __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
340 const int acl_type /* ACCESS vs. DEFAULT */);
341extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, 346extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
342 const unsigned char *searchName, 347 const unsigned char *searchName,
343 char *acl_inf, const int buflen, const int acl_type, 348 char *acl_inf, const int buflen, const int acl_type,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f0d9a485d095..59d7b7c037ad 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -647,8 +647,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
647 count - 16, 647 count - 16,
648 &server->secType); 648 &server->secType);
649 if (rc == 1) { 649 if (rc == 1) {
650 /* BB Need to fill struct for sessetup here */ 650 rc = 0;
651 rc = -EOPNOTSUPP;
652 } else { 651 } else {
653 rc = -EINVAL; 652 rc = -EINVAL;
654 } 653 }
@@ -2486,6 +2485,7 @@ querySymLinkRetry:
2486 return rc; 2485 return rc;
2487} 2486}
2488 2487
2488#ifdef CONFIG_CIFS_EXPERIMENTAL
2489/* Initialize NT TRANSACT SMB into small smb request buffer. 2489/* Initialize NT TRANSACT SMB into small smb request buffer.
2490 This assumes that all NT TRANSACTS that we init here have 2490 This assumes that all NT TRANSACTS that we init here have
2491 total parm and data under about 400 bytes (to fit in small cifs 2491 total parm and data under about 400 bytes (to fit in small cifs
@@ -2494,7 +2494,7 @@ querySymLinkRetry:
2494 MaxSetupCount (size of returned setup area) and 2494 MaxSetupCount (size of returned setup area) and
2495 MaxParameterCount (returned parms size) must be set by caller */ 2495 MaxParameterCount (returned parms size) must be set by caller */
2496static int 2496static int
2497smb_init_ntransact(const __u16 sub_command, const int setup_count, 2497smb_init_nttransact(const __u16 sub_command, const int setup_count,
2498 const int parm_len, struct cifsTconInfo *tcon, 2498 const int parm_len, struct cifsTconInfo *tcon,
2499 void **ret_buf) 2499 void **ret_buf)
2500{ 2500{
@@ -2525,12 +2525,15 @@ smb_init_ntransact(const __u16 sub_command, const int setup_count,
2525 2525
2526static int 2526static int
2527validate_ntransact(char *buf, char **ppparm, char **ppdata, 2527validate_ntransact(char *buf, char **ppparm, char **ppdata,
2528 int *pdatalen, int *pparmlen) 2528 __u32 *pparmlen, __u32 *pdatalen)
2529{ 2529{
2530 char *end_of_smb; 2530 char *end_of_smb;
2531 __u32 data_count, data_offset, parm_count, parm_offset; 2531 __u32 data_count, data_offset, parm_count, parm_offset;
2532 struct smb_com_ntransact_rsp *pSMBr; 2532 struct smb_com_ntransact_rsp *pSMBr;
2533 2533
2534 *pdatalen = 0;
2535 *pparmlen = 0;
2536
2534 if (buf == NULL) 2537 if (buf == NULL)
2535 return -EINVAL; 2538 return -EINVAL;
2536 2539
@@ -2567,8 +2570,11 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
2567 cFYI(1, ("parm count and data count larger than SMB")); 2570 cFYI(1, ("parm count and data count larger than SMB"));
2568 return -EINVAL; 2571 return -EINVAL;
2569 } 2572 }
2573 *pdatalen = data_count;
2574 *pparmlen = parm_count;
2570 return 0; 2575 return 0;
2571} 2576}
2577#endif /* CIFS_EXPERIMENTAL */
2572 2578
2573int 2579int
2574CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, 2580CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
@@ -3067,8 +3073,7 @@ GetExtAttrOut:
3067/* Get Security Descriptor (by handle) from remote server for a file or dir */ 3073/* Get Security Descriptor (by handle) from remote server for a file or dir */
3068int 3074int
3069CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, 3075CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3070 /* BB fix up return info */ char *acl_inf, const int buflen, 3076 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3071 const int acl_type)
3072{ 3077{
3073 int rc = 0; 3078 int rc = 0;
3074 int buf_type = 0; 3079 int buf_type = 0;
@@ -3077,7 +3082,10 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3077 3082
3078 cFYI(1, ("GetCifsACL")); 3083 cFYI(1, ("GetCifsACL"));
3079 3084
3080 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 3085 *pbuflen = 0;
3086 *acl_inf = NULL;
3087
3088 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3081 8 /* parm len */, tcon, (void **) &pSMB); 3089 8 /* parm len */, tcon, (void **) &pSMB);
3082 if (rc) 3090 if (rc)
3083 return rc; 3091 return rc;
@@ -3099,34 +3107,52 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3099 if (rc) { 3107 if (rc) {
3100 cFYI(1, ("Send error in QuerySecDesc = %d", rc)); 3108 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3101 } else { /* decode response */ 3109 } else { /* decode response */
3102 struct cifs_ntsd *psec_desc;
3103 __le32 * parm; 3110 __le32 * parm;
3104 int parm_len; 3111 __u32 parm_len;
3105 int data_len; 3112 __u32 acl_len;
3106 int acl_len;
3107 struct smb_com_ntransact_rsp *pSMBr; 3113 struct smb_com_ntransact_rsp *pSMBr;
3114 char *pdata;
3108 3115
3109/* validate_nttransact */ 3116/* validate_nttransact */
3110 rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 3117 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3111 (char **)&psec_desc, 3118 &pdata, &parm_len, pbuflen);
3112 &parm_len, &data_len);
3113 if (rc) 3119 if (rc)
3114 goto qsec_out; 3120 goto qsec_out;
3115 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base; 3121 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3116 3122
3117 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc)); 3123 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3118 3124
3119 if (le32_to_cpu(pSMBr->ParameterCount) != 4) { 3125 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3120 rc = -EIO; /* bad smb */ 3126 rc = -EIO; /* bad smb */
3127 *pbuflen = 0;
3121 goto qsec_out; 3128 goto qsec_out;
3122 } 3129 }
3123 3130
3124/* BB check that data area is minimum length and as big as acl_len */ 3131/* BB check that data area is minimum length and as big as acl_len */
3125 3132
3126 acl_len = le32_to_cpu(*parm); 3133 acl_len = le32_to_cpu(*parm);
3127 /* BB check if (acl_len > bufsize) */ 3134 if (acl_len != *pbuflen) {
3135 cERROR(1, ("acl length %d does not match %d",
3136 acl_len, *pbuflen));
3137 if (*pbuflen > acl_len)
3138 *pbuflen = acl_len;
3139 }
3128 3140
3129 parse_sec_desc(psec_desc, acl_len); 3141 /* check if buffer is big enough for the acl
3142 header followed by the smallest SID */
3143 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3144 (*pbuflen >= 64 * 1024)) {
3145 cERROR(1, ("bad acl length %d", *pbuflen));
3146 rc = -EINVAL;
3147 *pbuflen = 0;
3148 } else {
3149 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3150 if (*acl_inf == NULL) {
3151 *pbuflen = 0;
3152 rc = -ENOMEM;
3153 }
3154 memcpy(*acl_inf, pdata, *pbuflen);
3155 }
3130 } 3156 }
3131qsec_out: 3157qsec_out:
3132 if (buf_type == CIFS_SMALL_BUFFER) 3158 if (buf_type == CIFS_SMALL_BUFFER)
@@ -3381,7 +3407,7 @@ UnixQPathInfoRetry:
3381 memcpy((char *) pFindData, 3407 memcpy((char *) pFindData,
3382 (char *) &pSMBr->hdr.Protocol + 3408 (char *) &pSMBr->hdr.Protocol +
3383 data_offset, 3409 data_offset,
3384 sizeof (FILE_UNIX_BASIC_INFO)); 3410 sizeof(FILE_UNIX_BASIC_INFO));
3385 } 3411 }
3386 } 3412 }
3387 cifs_buf_release(pSMB); 3413 cifs_buf_release(pSMB);
@@ -3649,7 +3675,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3649 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); 3675 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3650 pSMB->SearchHandle = searchHandle; /* always kept as le */ 3676 pSMB->SearchHandle = searchHandle; /* always kept as le */
3651 pSMB->SearchCount = 3677 pSMB->SearchCount =
3652 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO)); 3678 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3653 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); 3679 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3654 pSMB->ResumeKey = psrch_inf->resume_key; 3680 pSMB->ResumeKey = psrch_inf->resume_key;
3655 pSMB->SearchFlags = 3681 pSMB->SearchFlags =
@@ -4331,7 +4357,7 @@ QFSDeviceRetry:
4331 } else { /* decode response */ 4357 } else { /* decode response */
4332 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 4358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4333 4359
4334 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO))) 4360 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4335 rc = -EIO; /* bad smb */ 4361 rc = -EIO; /* bad smb */
4336 else { 4362 else {
4337 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 4363 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 19ee11f7f35a..1102160f6661 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -793,7 +793,7 @@ cifs_parse_mount_options(char *options, const char *devname,
793 vol->linux_gid = current->gid; 793 vol->linux_gid = current->gid;
794 vol->dir_mode = S_IRWXUGO; 794 vol->dir_mode = S_IRWXUGO;
795 /* 2767 perms indicate mandatory locking support */ 795 /* 2767 perms indicate mandatory locking support */
796 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); 796 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
797 797
798 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ 798 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
799 vol->rw = TRUE; 799 vol->rw = TRUE;
@@ -1790,7 +1790,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1790 1790
1791 if (volume_info.nullauth) { 1791 if (volume_info.nullauth) {
1792 cFYI(1, ("null user")); 1792 cFYI(1, ("null user"));
1793 volume_info.username = NULL; 1793 volume_info.username = "";
1794 } else if (volume_info.username) { 1794 } else if (volume_info.username) {
1795 /* BB fixme parse for domain name here */ 1795 /* BB fixme parse for domain name here */
1796 cFYI(1, ("Username: %s", volume_info.username)); 1796 cFYI(1, ("Username: %s", volume_info.username));
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 793404b10925..37dc97af1487 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -593,7 +593,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
593 * case take precedence. If a is not a negative dentry, this 593 * case take precedence. If a is not a negative dentry, this
594 * should have no side effects 594 * should have no side effects
595 */ 595 */
596 memcpy((unsigned char *)a->name, b->name, a->len); 596 memcpy(a->name, b->name, a->len);
597 return 0; 597 return 0;
598 } 598 }
599 return 1; 599 return 1;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1e7e4c06d9e3..68ad4ca0cfa3 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1026,6 +1026,37 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
1026 return total_written; 1026 return total_written;
1027} 1027}
1028 1028
1029#ifdef CONFIG_CIFS_EXPERIMENTAL
1030struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1031{
1032 struct cifsFileInfo *open_file = NULL;
1033
1034 read_lock(&GlobalSMBSeslock);
1035 /* we could simply get the first_list_entry since write-only entries
1036 are always at the end of the list but since the first entry might
1037 have a close pending, we go through the whole list */
1038 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1039 if (open_file->closePend)
1040 continue;
1041 if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
1042 (open_file->pfile->f_flags & O_RDONLY))) {
1043 if (!open_file->invalidHandle) {
1044 /* found a good file */
1045 /* lock it so it will not be closed on us */
1046 atomic_inc(&open_file->wrtPending);
1047 read_unlock(&GlobalSMBSeslock);
1048 return open_file;
1049 } /* else might as well continue, and look for
1050 another, or simply have the caller reopen it
1051 again rather than trying to fix this handle */
1052 } else /* write only file */
1053 break; /* write only files are last so must be done */
1054 }
1055 read_unlock(&GlobalSMBSeslock);
1056 return NULL;
1057}
1058#endif
1059
1029struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) 1060struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
1030{ 1061{
1031 struct cifsFileInfo *open_file; 1062 struct cifsFileInfo *open_file;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 5e8b388be3b6..7d907e84e032 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -289,7 +289,7 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
289 289
290#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ 290#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
291 291
292static int get_sfu_uid_mode(struct inode *inode, 292static int get_sfu_mode(struct inode *inode,
293 const unsigned char *path, 293 const unsigned char *path,
294 struct cifs_sb_info *cifs_sb, int xid) 294 struct cifs_sb_info *cifs_sb, int xid)
295{ 295{
@@ -527,11 +527,16 @@ int cifs_get_inode_info(struct inode **pinode,
527 527
528 /* BB fill in uid and gid here? with help from winbind? 528 /* BB fill in uid and gid here? with help from winbind?
529 or retrieve from NTFS stream extended attribute */ 529 or retrieve from NTFS stream extended attribute */
530#ifdef CONFIG_CIFS_EXPERIMENTAL
531 /* fill in 0777 bits from ACL */
532 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
533 cFYI(1, ("Getting mode bits from ACL"));
534 acl_to_uid_mode(inode, search_path);
535 }
536#endif
530 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 537 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
531 /* fill in uid, gid, mode from server ACL */ 538 /* fill in remaining high mode bits e.g. SUID, VTX */
532 /* BB FIXME this should also take into account the 539 get_sfu_mode(inode, search_path, cifs_sb, xid);
533 * default uid specified on mount if present */
534 get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
535 } else if (atomic_read(&cifsInfo->inUse) == 0) { 540 } else if (atomic_read(&cifsInfo->inUse) == 0) {
536 inode->i_uid = cifs_sb->mnt_uid; 541 inode->i_uid = cifs_sb->mnt_uid;
537 inode->i_gid = cifs_sb->mnt_gid; 542 inode->i_gid = cifs_sb->mnt_gid;
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c
index e5c3e1212697..f13f96d42fcf 100644
--- a/fs/cifs/md5.c
+++ b/fs/cifs/md5.c
@@ -276,8 +276,8 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len,
276 } 276 }
277 277
278 /* start out by storing key in pads */ 278 /* start out by storing key in pads */
279 memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); 279 memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
280 memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); 280 memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
281 memcpy(ctx->k_ipad, key, key_len); 281 memcpy(ctx->k_ipad, key, key_len);
282 memcpy(ctx->k_opad, key, key_len); 282 memcpy(ctx->k_opad, key, key_len);
283 283
@@ -307,8 +307,8 @@ hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
307 } 307 }
308 308
309 /* start out by storing key in pads */ 309 /* start out by storing key in pads */
310 memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); 310 memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
311 memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); 311 memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
312 memcpy(ctx->k_ipad, key, key_len); 312 memcpy(ctx->k_ipad, key, key_len);
313 memcpy(ctx->k_opad, key, key_len); 313 memcpy(ctx->k_opad, key, key_len);
314 314
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 51ec681fe74a..15546c2354c5 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -73,7 +73,7 @@ sesInfoAlloc(void)
73{ 73{
74 struct cifsSesInfo *ret_buf; 74 struct cifsSesInfo *ret_buf;
75 75
76 ret_buf = kzalloc(sizeof (struct cifsSesInfo), GFP_KERNEL); 76 ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
77 if (ret_buf) { 77 if (ret_buf) {
78 write_lock(&GlobalSMBSeslock); 78 write_lock(&GlobalSMBSeslock);
79 atomic_inc(&sesInfoAllocCount); 79 atomic_inc(&sesInfoAllocCount);
@@ -109,7 +109,7 @@ struct cifsTconInfo *
109tconInfoAlloc(void) 109tconInfoAlloc(void)
110{ 110{
111 struct cifsTconInfo *ret_buf; 111 struct cifsTconInfo *ret_buf;
112 ret_buf = kzalloc(sizeof (struct cifsTconInfo), GFP_KERNEL); 112 ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
113 if (ret_buf) { 113 if (ret_buf) {
114 write_lock(&GlobalSMBSeslock); 114 write_lock(&GlobalSMBSeslock);
115 atomic_inc(&tconInfoAllocCount); 115 atomic_inc(&tconInfoAllocCount);
@@ -298,7 +298,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
298 memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ 298 memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
299 299
300 buffer->smb_buf_length = 300 buffer->smb_buf_length =
301 (2 * word_count) + sizeof (struct smb_hdr) - 301 (2 * word_count) + sizeof(struct smb_hdr) -
302 4 /* RFC 1001 length field does not count */ + 302 4 /* RFC 1001 length field does not count */ +
303 2 /* for bcc field itself */ ; 303 2 /* for bcc field itself */ ;
304 /* Note that this is the only network field that has to be converted 304 /* Note that this is the only network field that has to be converted
@@ -422,8 +422,8 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
422 __u32 clc_len; /* calculated length */ 422 __u32 clc_len; /* calculated length */
423 cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len)); 423 cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
424 424
425 if (length < 2 + sizeof (struct smb_hdr)) { 425 if (length < 2 + sizeof(struct smb_hdr)) {
426 if ((length >= sizeof (struct smb_hdr) - 1) 426 if ((length >= sizeof(struct smb_hdr) - 1)
427 && (smb->Status.CifsError != 0)) { 427 && (smb->Status.CifsError != 0)) {
428 smb->WordCount = 0; 428 smb->WordCount = 0;
429 /* some error cases do not return wct and bcc */ 429 /* some error cases do not return wct and bcc */
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index f06359cb22ee..646e1f06941b 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -132,6 +132,34 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
132 {0, 0} 132 {0, 0}
133}; 133};
134 134
135
136/* if the mount helper is missing we need to reverse the 1st slash
137 from '/' to backslash in order to format the UNC properly for
138 ip address parsing and for tree connect (unless the user
139 remembered to put the UNC name in properly). Fortunately we do
140 not have to call this twice (we check for IPv4 addresses
141 first, so it is already converted by the time we
142 try IPv6 addresses */
143static int canonicalize_unc(char *cp)
144{
145 int i;
146
147 for (i = 0; i <= 46 /* INET6_ADDRSTRLEN */ ; i++) {
148 if (cp[i] == 0)
149 break;
150 if (cp[i] == '\\')
151 break;
152 if (cp[i] == '/') {
153#ifdef CONFIG_CIFS_DEBUG2
154 cFYI(1, ("change slash to backslash in malformed UNC"));
155#endif
156 cp[i] = '\\';
157 return 1;
158 }
159 }
160 return 0;
161}
162
135/* Convert string containing dotted ip address to binary form */ 163/* Convert string containing dotted ip address to binary form */
136/* returns 0 if invalid address */ 164/* returns 0 if invalid address */
137 165
@@ -141,11 +169,13 @@ cifs_inet_pton(int address_family, char *cp, void *dst)
141 int ret = 0; 169 int ret = 0;
142 170
143 /* calculate length by finding first slash or NULL */ 171 /* calculate length by finding first slash or NULL */
144 /* BB Should we convert '/' slash to '\' here since it seems already 172 if (address_family == AF_INET) {
145 * done before this */ 173 ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL);
146 if ( address_family == AF_INET ) { 174 if (ret == 0) {
147 ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL); 175 if (canonicalize_unc(cp))
148 } else if ( address_family == AF_INET6 ) { 176 ret = in4_pton(cp, -1, dst, '\\', NULL);
177 }
178 } else if (address_family == AF_INET6) {
149 ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL); 179 ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
150 } 180 }
151#ifdef CONFIG_CIFS_DEBUG2 181#ifdef CONFIG_CIFS_DEBUG2
@@ -740,7 +770,7 @@ cifs_print_status(__u32 status_code)
740 770
741 771
742static void 772static void
743ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) 773ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
744{ 774{
745 int i; 775 int i;
746 if (ntstatus == 0) { 776 if (ntstatus == 0) {
@@ -793,8 +823,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
793 if (smberrclass == ERRDOS) { /* 1 byte field no need to byte reverse */ 823 if (smberrclass == ERRDOS) { /* 1 byte field no need to byte reverse */
794 for (i = 0; 824 for (i = 0;
795 i < 825 i <
796 sizeof (mapping_table_ERRDOS) / 826 sizeof(mapping_table_ERRDOS) /
797 sizeof (struct smb_to_posix_error); i++) { 827 sizeof(struct smb_to_posix_error); i++) {
798 if (mapping_table_ERRDOS[i].smb_err == 0) 828 if (mapping_table_ERRDOS[i].smb_err == 0)
799 break; 829 break;
800 else if (mapping_table_ERRDOS[i].smb_err == 830 else if (mapping_table_ERRDOS[i].smb_err ==
@@ -807,8 +837,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
807 } else if (smberrclass == ERRSRV) { /* server class of error codes */ 837 } else if (smberrclass == ERRSRV) { /* server class of error codes */
808 for (i = 0; 838 for (i = 0;
809 i < 839 i <
810 sizeof (mapping_table_ERRSRV) / 840 sizeof(mapping_table_ERRSRV) /
811 sizeof (struct smb_to_posix_error); i++) { 841 sizeof(struct smb_to_posix_error); i++) {
812 if (mapping_table_ERRSRV[i].smb_err == 0) 842 if (mapping_table_ERRSRV[i].smb_err == 0)
813 break; 843 break;
814 else if (mapping_table_ERRSRV[i].smb_err == 844 else if (mapping_table_ERRSRV[i].smb_err ==
@@ -837,14 +867,14 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
837unsigned int 867unsigned int
838smbCalcSize(struct smb_hdr *ptr) 868smbCalcSize(struct smb_hdr *ptr)
839{ 869{
840 return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + 870 return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
841 2 /* size of the bcc field */ + BCC(ptr)); 871 2 /* size of the bcc field */ + BCC(ptr));
842} 872}
843 873
844unsigned int 874unsigned int
845smbCalcSize_LE(struct smb_hdr *ptr) 875smbCalcSize_LE(struct smb_hdr *ptr)
846{ 876{
847 return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + 877 return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
848 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); 878 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr)));
849} 879}
850 880
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 3746580e9701..0f22def4bdff 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -171,7 +171,13 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
171 /* Linux can not store file creation time unfortunately so ignore it */ 171 /* Linux can not store file creation time unfortunately so ignore it */
172 172
173 cifsInfo->cifsAttrs = attr; 173 cifsInfo->cifsAttrs = attr;
174 cifsInfo->time = jiffies; 174#ifdef CONFIG_CIFS_EXPERIMENTAL
175 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
176 /* get more accurate mode via ACL - so force inode refresh */
177 cifsInfo->time = 0;
178 } else
179#endif /* CONFIG_CIFS_EXPERIMENTAL */
180 cifsInfo->time = jiffies;
175 181
176 /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ 182 /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
177 /* 2767 perms - indicate mandatory locking */ 183 /* 2767 perms - indicate mandatory locking */
@@ -495,7 +501,7 @@ ffirst_retry:
495static int cifs_unicode_bytelen(char *str) 501static int cifs_unicode_bytelen(char *str)
496{ 502{
497 int len; 503 int len;
498 __le16 * ustr = (__le16 *)str; 504 __le16 *ustr = (__le16 *)str;
499 505
500 for (len = 0; len <= PATH_MAX; len++) { 506 for (len = 0; len <= PATH_MAX; len++) {
501 if (ustr[len] == 0) 507 if (ustr[len] == 0)
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index 90542a39be17..58bbfd992cc0 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -80,7 +80,7 @@ SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
80 80
81/* Routines for Windows NT MD4 Hash functions. */ 81/* Routines for Windows NT MD4 Hash functions. */
82static int 82static int
83_my_wcslen(__u16 * str) 83_my_wcslen(__u16 *str)
84{ 84{
85 int len = 0; 85 int len = 0;
86 while (*str++ != 0) 86 while (*str++ != 0)
@@ -96,7 +96,7 @@ _my_wcslen(__u16 * str)
96 */ 96 */
97 97
98static int 98static int
99_my_mbstowcs(__u16 * dst, const unsigned char *src, int len) 99_my_mbstowcs(__u16 *dst, const unsigned char *src, int len)
100{ /* BB not a very good conversion routine - change/fix */ 100{ /* BB not a very good conversion routine - change/fix */
101 int i; 101 int i;
102 __u16 val; 102 __u16 val;
@@ -125,9 +125,9 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
125 /* Password cannot be longer than 128 characters */ 125 /* Password cannot be longer than 128 characters */
126 if (passwd) { 126 if (passwd) {
127 len = strlen((char *) passwd); 127 len = strlen((char *) passwd);
128 if (len > 128) { 128 if (len > 128)
129 len = 128; 129 len = 128;
130 } 130
131 /* Password must be converted to NT unicode */ 131 /* Password must be converted to NT unicode */
132 _my_mbstowcs(wpwd, passwd, len); 132 _my_mbstowcs(wpwd, passwd, len);
133 } else 133 } else
@@ -135,7 +135,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
135 135
136 wpwd[len] = 0; /* Ensure string is null terminated */ 136 wpwd[len] = 0; /* Ensure string is null terminated */
137 /* Calculate length in bytes */ 137 /* Calculate length in bytes */
138 len = _my_wcslen(wpwd) * sizeof (__u16); 138 len = _my_wcslen(wpwd) * sizeof(__u16);
139 139
140 mdfour(p16, (unsigned char *) wpwd, len); 140 mdfour(p16, (unsigned char *) wpwd, len);
141 memset(wpwd, 0, 129 * 2); 141 memset(wpwd, 0, 129 * 2);
@@ -167,7 +167,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
167 E_P16((unsigned char *) passwd, (unsigned char *) p16); 167 E_P16((unsigned char *) passwd, (unsigned char *) p16);
168 168
169 /* clear out local copy of user's password (just being paranoid). */ 169 /* clear out local copy of user's password (just being paranoid). */
170 memset(passwd, '\0', sizeof (passwd)); 170 memset(passwd, '\0', sizeof(passwd));
171} 171}
172#endif 172#endif
173 173
@@ -189,8 +189,10 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
189 return; 189 return;
190 dom_u = user_u + 1024; 190 dom_u = user_u + 1024;
191 191
192 /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); 192 /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2,
193 push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ 193 STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
194 push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2,
195 STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
194 196
195 /* BB user and domain may need to be uppercased */ 197 /* BB user and domain may need to be uppercased */
196 user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); 198 user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 369e838bebd3..54e8ef96cb79 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -265,7 +265,9 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
265 else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 265 else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
266 __u16 fid; 266 __u16 fid;
267 int oplock = FALSE; 267 int oplock = FALSE;
268 if (experimEnabled) 268 struct cifs_ntsd *pacl = NULL;
269 __u32 buflen = 0;
270 if (experimEnabled)
269 rc = CIFSSMBOpen(xid, pTcon, full_path, 271 rc = CIFSSMBOpen(xid, pTcon, full_path,
270 FILE_OPEN, GENERIC_READ, 0, &fid, 272 FILE_OPEN, GENERIC_READ, 0, &fid,
271 &oplock, NULL, cifs_sb->local_nls, 273 &oplock, NULL, cifs_sb->local_nls,
@@ -273,10 +275,9 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
273 CIFS_MOUNT_MAP_SPECIAL_CHR); 275 CIFS_MOUNT_MAP_SPECIAL_CHR);
274 /* else rc is EOPNOTSUPP from above */ 276 /* else rc is EOPNOTSUPP from above */
275 277
276 if(rc == 0) { 278 if (rc == 0) {
277 rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, 279 rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl,
278 ea_value, buf_size, 280 &buflen);
279 ACL_TYPE_ACCESS);
280 CIFSSMBClose(xid, pTcon, fid); 281 CIFSSMBClose(xid, pTcon, fid);
281 } 282 }
282 } 283 }