diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-12 14:11:39 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-12 14:11:39 -0500 |
commit | 46015977e70f672ae6b20a1b5fb1e361208365ba (patch) | |
tree | e3be0785eff90cc8023cd1ea03fc22d3dcf37f41 /fs | |
parent | 92d140e21f1ce8cf99320afbbcad73879128e6dc (diff) | |
parent | 9b8f5f573770f33b28c45255ac82e6457278c782 (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')
-rw-r--r-- | fs/Kconfig | 2 | ||||
-rw-r--r-- | fs/cifs/CHANGES | 11 | ||||
-rw-r--r-- | fs/cifs/Makefile | 7 | ||||
-rw-r--r-- | fs/cifs/asn1.c | 35 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 128 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.h | 46 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 346 | ||||
-rw-r--r-- | fs/cifs/cifsacl.h | 17 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 9 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 17 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 40 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 11 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 64 | ||||
-rw-r--r-- | fs/cifs/connect.c | 4 | ||||
-rw-r--r-- | fs/cifs/dir.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 31 | ||||
-rw-r--r-- | fs/cifs/inode.c | 15 | ||||
-rw-r--r-- | fs/cifs/md5.c | 8 | ||||
-rw-r--r-- | fs/cifs/misc.c | 10 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 54 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 10 | ||||
-rw-r--r-- | fs/cifs/smbencrypt.c | 18 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 11 |
24 files changed, 727 insertions, 171 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index c75c95406497..429a00228507 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -2007,7 +2007,7 @@ config CIFS_EXPERIMENTAL | |||
2007 | config CIFS_UPCALL | 2007 | config CIFS_UPCALL |
2008 | bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" | 2008 | bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" |
2009 | depends on CIFS_EXPERIMENTAL | 2009 | depends on CIFS_EXPERIMENTAL |
2010 | depends on CONNECTOR | 2010 | depends on KEYS |
2011 | help | 2011 | help |
2012 | Enables an upcall mechanism for CIFS which will be used to contact | 2012 | Enables an upcall mechanism for CIFS which will be used to contact |
2013 | userspace helper utilities to provide SPNEGO packaged Kerberos | 2013 | userspace helper utilities to provide SPNEGO packaged Kerberos |
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 @@ | |||
1 | Version 1.52 | ||
2 | ------------ | ||
3 | Fix oops on second mount to server when null auth is used. | ||
4 | |||
1 | Version 1.51 | 5 | Version 1.51 |
2 | ------------ | 6 | ------------ |
3 | Fix memory leak in statfs when mounted to very old servers (e.g. | 7 | Fix 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 | |||
12 | cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on | 16 | cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on |
13 | bigendian architectures. Fix possible memory corruption when | 17 | bigendian architectures. Fix possible memory corruption when |
14 | EAGAIN returned on kern_recvmsg. Return better error if server | 18 | EAGAIN returned on kern_recvmsg. Return better error if server |
15 | requires packet signing but client has disabled it. | 19 | requires packet signing but client has disabled it. When mounted |
20 | with cifsacl mount option - mode bits are approximated based | ||
21 | on the contents of the ACL of the file or directory. When cifs | ||
22 | mount helper is missing convert make sure that UNC name | ||
23 | has backslash (not forward slash) between ip address of server | ||
24 | and the share name. | ||
16 | 25 | ||
17 | Version 1.50 | 26 | Version 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 | # |
4 | obj-$(CONFIG_CIFS) += cifs.o | 4 | obj-$(CONFIG_CIFS) += cifs.o |
5 | 5 | ||
6 | cifs-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 | 6 | cifs-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 | |||
11 | cifs-$(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 | ||
80 | static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; | 82 | static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; |
81 | static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; | 83 | static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; |
84 | static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 }; | ||
85 | static 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 */ | ||
31 | static int | ||
32 | cifs_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 | |||
47 | error: | ||
48 | return ret; | ||
49 | } | ||
50 | |||
51 | static void | ||
52 | cifs_spnego_key_destroy(struct key *key) | ||
53 | { | ||
54 | kfree(key->payload.data); | ||
55 | } | ||
56 | |||
57 | |||
58 | /* | ||
59 | * keytype for CIFS spnego keys | ||
60 | */ | ||
61 | struct 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 */ | ||
70 | struct key * | ||
71 | cifs_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 | |||
125 | out: | ||
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 | */ | ||
34 | struct 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__ | ||
43 | extern 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 */ |
46 | static const struct cifs_sid sid_everyone = | 46 | static 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 */ |
49 | static const struct cifs_sid sid_user = | 49 | static 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 */ |
100 | int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) | 100 | int 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 | */ | ||
137 | static 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 | |||
197 | static 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 | ||
133 | static void parse_ace(struct cifs_ace *pace, char *end_of_acl) | 223 | #ifdef CONFIG_CIFS_DEBUG2 |
224 | static 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 | |||
166 | static 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 | ||
184 | static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | 260 | static 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 | ||
258 | static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | 347 | static 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 */ |
292 | int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) | 381 | static 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 */ | ||
434 | static 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 */ | ||
489 | void 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 */ | ||
511 | int 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 | |||
38 | struct cifs_ntsd { | 41 | struct 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 | ||
54 | struct cifs_acl { | 57 | struct 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 | ||
60 | struct cifs_ntace { /* first part of ACE which contains perms */ | 63 | struct 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 | |||
67 | struct 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 | ||
74 | struct cifs_wksid { | 71 | struct cifs_wksid { |
@@ -79,7 +76,7 @@ struct cifs_wksid { | |||
79 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 76 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
80 | 77 | ||
81 | extern int match_sid(struct cifs_sid *); | 78 | extern int match_sid(struct cifs_sid *); |
82 | extern int compare_sids(struct cifs_sid *, struct cifs_sid *); | 79 | extern 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 | ||
124 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | 125 | int 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, | |||
106 | extern const struct export_operations cifs_export_ops; | 106 | extern 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 | |||
1232 | typedef 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 | |||
1214 | typedef struct smb_com_transaction_change_notify_req { | 1254 | typedef 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); | |||
61 | extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); | 61 | extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); |
62 | extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); | 62 | extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); |
63 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); | 63 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); |
64 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
65 | extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *); | ||
66 | #endif | ||
64 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); | 67 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); |
65 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | 68 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); |
66 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 69 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
@@ -73,6 +76,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ , | |||
73 | extern int small_smb_init_no_tc(const int smb_cmd, const int wct, | 76 | extern 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); |
79 | extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo, | ||
80 | const char *hostname); | ||
76 | extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | 81 | extern 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, | |||
92 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 97 | extern 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); |
100 | extern void acl_to_uid_mode(struct inode *inode, const char *search_path); | ||
101 | extern int mode_to_acl(struct inode *inode, const char *path); | ||
95 | 102 | ||
96 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 103 | extern 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 |
312 | extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key); | 319 | extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key); |
313 | #endif /* CIFS_WEAK_PW_HASH */ | 320 | #endif /* CIFS_WEAK_PW_HASH */ |
314 | extern int parse_sec_desc(struct cifs_ntsd *, int); | ||
315 | extern int CIFSSMBCopy(int xid, | 321 | extern 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); |
338 | extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, | 344 | extern 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 */); | ||
341 | extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, | 346 | extern 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 */ |
2496 | static int | 2496 | static int |
2497 | smb_init_ntransact(const __u16 sub_command, const int setup_count, | 2497 | smb_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 | ||
2526 | static int | 2526 | static int |
2527 | validate_ntransact(char *buf, char **ppparm, char **ppdata, | 2527 | validate_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 | ||
2573 | int | 2579 | int |
2574 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | 2580 | CIFSSMBQueryReparseLinkInfo(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 */ |
3068 | int | 3074 | int |
3069 | CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | 3075 | CIFSSMBGetCIFSACL(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 | } |
3131 | qsec_out: | 3157 | qsec_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 | ||
1030 | struct 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 | |||
1029 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | 1060 | struct 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 | ||
292 | static int get_sfu_uid_mode(struct inode *inode, | 292 | static 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 * | |||
109 | tconInfoAlloc(void) | 109 | tconInfoAlloc(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 */ | ||
143 | static 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 | ||
742 | static void | 772 | static void |
743 | ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) | 773 | ntstatus_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) | |||
837 | unsigned int | 867 | unsigned int |
838 | smbCalcSize(struct smb_hdr *ptr) | 868 | smbCalcSize(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 | ||
844 | unsigned int | 874 | unsigned int |
845 | smbCalcSize_LE(struct smb_hdr *ptr) | 875 | smbCalcSize_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: | |||
495 | static int cifs_unicode_bytelen(char *str) | 501 | static 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. */ |
82 | static int | 82 | static 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 | ||
98 | static int | 98 | static 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 | } |