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