Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 236521 Details for
Bug 315311
Add Kerberos support to CIFS mounts
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
patch -- add upcalls using keyctl for CIFS auth
cifs-spnego-upcall.patch (text/plain), 34.73 KB, created by
Jeff Layton
on 2007-10-24 19:26:06 UTC
(
hide
)
Description:
patch -- add upcalls using keyctl for CIFS auth
Filename:
MIME Type:
Creator:
Jeff Layton
Created:
2007-10-24 19:26:06 UTC
Size:
34.73 KB
patch
obsolete
>diff --git a/Documentation/keys-request-key.txt b/Documentation/keys-request-key.txt >index 266955d..09b55e4 100644 >--- a/Documentation/keys-request-key.txt >+++ b/Documentation/keys-request-key.txt >@@ -11,26 +11,29 @@ request_key*(): > > struct key *request_key(const struct key_type *type, > const char *description, >- const char *callout_string); >+ const char *callout_info); > > or: > > struct key *request_key_with_auxdata(const struct key_type *type, > const char *description, >- const char *callout_string, >+ const char *callout_info, >+ size_t callout_len, > void *aux); > > or: > > struct key *request_key_async(const struct key_type *type, > const char *description, >- const char *callout_string); >+ const char *callout_info, >+ size_t callout_len); > > or: > > struct key *request_key_async_with_auxdata(const struct key_type *type, > const char *description, >- const char *callout_string, >+ const char *callout_info, >+ size_t callout_len, > void *aux); > > Or by userspace invoking the request_key system call: >diff --git a/Documentation/keys.txt b/Documentation/keys.txt >index 51652d3..b82d38d 100644 >--- a/Documentation/keys.txt >+++ b/Documentation/keys.txt >@@ -771,7 +771,7 @@ payload contents" for more information. > > struct key *request_key(const struct key_type *type, > const char *description, >- const char *callout_string); >+ const char *callout_info); > > This is used to request a key or keyring with a description that matches > the description specified according to the key type's match function. This >@@ -793,24 +793,28 @@ payload contents" for more information. > > struct key *request_key_with_auxdata(const struct key_type *type, > const char *description, >- const char *callout_string, >+ const void *callout_info, >+ size_t callout_len, > void *aux); > > This is identical to request_key(), except that the auxiliary data is >- passed to the key_type->request_key() op if it exists. >+ passed to the key_type->request_key() op if it exists, and the callout_info >+ is a blob of length callout_len, if given (the length may be 0). > > > (*) A key can be requested asynchronously by calling one of: > > struct key *request_key_async(const struct key_type *type, > const char *description, >- const char *callout_string); >+ const void *callout_info, >+ size_t callout_len); > > or: > > struct key *request_key_async_with_auxdata(const struct key_type *type, > const char *description, >- const char *callout_string, >+ const char *callout_info, >+ size_t callout_len, > void *aux); > > which are asynchronous equivalents of request_key() and >diff --git a/fs/Kconfig b/fs/Kconfig >index cc28a69..e431c38 100644 >--- a/fs/Kconfig >+++ b/fs/Kconfig >@@ -2007,7 +2007,7 @@ config CIFS_EXPERIMENTAL > config CIFS_UPCALL > bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" > depends on CIFS_EXPERIMENTAL >- depends on CONNECTOR >+ depends on KEYS > help > Enables an upcall mechanism for CIFS which will be used to contact > userspace helper utilities to provide SPNEGO packaged Kerberos >diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile >index ff6ba8d..0a6d9a5 100644 >--- a/fs/cifs/Makefile >+++ b/fs/cifs/Makefile >@@ -3,4 +3,4 @@ > # > obj-$(CONFIG_CIFS) += cifs.o > >-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 >+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 cifsauth.o >diff --git a/fs/cifs/cifsauth.c b/fs/cifs/cifsauth.c >new file mode 100644 >index 0000000..519c124 >--- /dev/null >+++ b/fs/cifs/cifsauth.c >@@ -0,0 +1,114 @@ >+/* >+ * fs/cifs/cifsauth.c -- auth management for CIFS >+ * >+ * Copyright (c) 2007 Red Hat, Inc. >+ * Author(s): Jeff Layton (jlayton@redhat.com) >+ * >+ * This library is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU Lesser General Public License as published >+ * by the Free Software Foundation; either version 2.1 of the License, or >+ * (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See >+ * the GNU Lesser General Public License for more details. >+ * >+ * You should have received a copy of the GNU Lesser General Public License >+ * along with this library; if not, write to the Free Software >+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >+ */ >+ >+#include <linux/list.h> >+#include <linux/string.h> >+#include <keys/user-type.h> >+#include <linux/key-type.h> >+#include "cifsglob.h" >+#include "cifsauth.h" >+#include "cifs_debug.h" >+ >+/* create a new cifs key */ >+static int >+cifs_key_instantiate(struct key *key, const void *data, size_t datalen) >+{ >+ char *payload; >+ int ret; >+ >+ ret = -ENOMEM; >+ payload = kmalloc(datalen, GFP_KERNEL); >+ if (!payload) >+ goto error; >+ >+ /* attach the data */ >+ memcpy(payload, data, datalen); >+ rcu_assign_pointer(key->payload.data, payload); >+ ret = 0; >+ >+error: >+ return ret; >+} >+ >+static void >+cifs_key_destroy(struct key *key) >+{ >+ kfree(key->payload.data); >+} >+ >+ >+/* >+ * keytype for CIFS spnego keys >+ */ >+struct key_type cifs_key_type = { >+ .name = "cifs", >+ .instantiate = cifs_key_instantiate, >+ .match = user_match, >+ .destroy = cifs_key_destroy, >+ .describe = user_describe, >+}; >+ >+/* get a key struct with a SPNEGO security blob, suitable for session setup */ >+struct key * >+cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const unsigned char *secblob, >+ size_t seclen, const char *hostname) >+{ >+ struct TCP_Server_Info *server = sesInfo->server; >+ char *description = NULL; >+ struct key *spnego_key; >+ >+ spnego_key = ERR_PTR(-ENOMEM); >+ /* version + ;ip{4|6}= + address + ; + host=hostname + NULL */ >+ description = kzalloc((2 + 5 + 32 + 1 + 5 + strlen(hostname) + 1), >+ GFP_KERNEL); >+ if (description == NULL) >+ goto out; >+ >+ spnego_key = ERR_PTR(-EINVAL); >+ if (server->addr.sockAddr.sin_family == AF_INET) >+ sprintf(description, "%2.2x;ip4=" NIPQUAD_FMT ";host=%s", >+ CIFS_AUTH_UPCALL_VERSION, >+ NIPQUAD(server->addr.sockAddr.sin_addr), >+ hostname); >+ else if (server->addr.sockAddr.sin_family == AF_INET6) >+ sprintf(description, "%2.2x;ip6=" NIP6_SEQFMT ";host=%s", >+ CIFS_AUTH_UPCALL_VERSION, >+ NIP6(server->addr.sockAddr6.sin6_addr), >+ hostname); >+ /* BB: anything special for SCTP? */ >+ else >+ goto out; >+ >+ cFYI(1,("key description = %s", description)); >+ spnego_key = request_key_with_auxdata(&cifs_key_type, description, >+ secblob, seclen, NULL); >+ >+ if (cifsFYI && !IS_ERR(spnego_key)) { >+ struct cifs_spnego_msg *msg = spnego_key->payload.data; >+ cifs_dump_mem("SPNEGO reply blob:", msg->data, >+ msg->secblob_len + msg->sesskey_len); >+ } >+ >+out: >+ if (description) >+ kfree(description); >+ return spnego_key; >+} >diff --git a/fs/cifs/cifsauth.h b/fs/cifs/cifsauth.h >new file mode 100644 >index 0000000..6ecfa04 >--- /dev/null >+++ b/fs/cifs/cifsauth.h >@@ -0,0 +1,37 @@ >+/* >+ * fs/cifs/cifsauth.h -- auth management for CIFS >+ * >+ * Copyright (c) 2007 Red Hat, Inc. >+ * Author(s): Jeff Layton (jlayton@redhat.com) >+ * >+ * This library is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU Lesser General Public License as published >+ * by the Free Software Foundation; either version 2.1 of the License, or >+ * (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See >+ * the GNU Lesser General Public License for more details. >+ * >+ * You should have received a copy of the GNU Lesser General Public License >+ * along with this library; if not, write to the Free Software >+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >+ */ >+ >+#ifndef _CIFSAUTH_H >+#define _CIFSAUTH_H >+ >+#define CIFS_AUTH_UPCALL_VERSION 1 >+ >+#define CIFS_AUTH_KRB5 0x0001 >+#define CIFS_AUTH_NTLMSSP 0x0002 >+ >+struct cifs_spnego_msg { >+ uint32_t flags; >+ uint32_t sesskey_len; >+ uint32_t secblob_len; >+ uint8_t data[1]; >+}; >+ >+#endif /* _CIFSAUTH_H */ >diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c >index 632070b..788f0ad 100644 >--- a/fs/cifs/cifsencrypt.c >+++ b/fs/cifs/cifsencrypt.c >@@ -99,11 +99,12 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, > MD5Init(&context); > MD5Update(&context, (char *)&key->data, key->len); > for (i = 0; i < n_vec; i++) { >+ if (iov[i].iov_len == 0) >+ continue; > if (iov[i].iov_base == NULL) { > cERROR(1, ("null iovec entry")); > return -EIO; >- } else if (iov[i].iov_len == 0) >- break; /* bail out if we are sent nothing to sign */ >+ } > /* The first entry includes a length field (which does not get > signed that occupies the first 4 bytes before the header */ > if (i == 0) { >diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c >index a6fbea5..e9da9b9 100644 >--- a/fs/cifs/cifsfs.c >+++ b/fs/cifs/cifsfs.c >@@ -43,6 +43,7 @@ > #include "cifs_debug.h" > #include "cifs_fs_sb.h" > #include <linux/mm.h> >+#include <linux/key-type.h> > #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ > > #ifdef CONFIG_CIFS_QUOTA >@@ -87,6 +88,7 @@ extern mempool_t *cifs_req_poolp; > extern mempool_t *cifs_mid_poolp; > > extern struct kmem_cache *cifs_oplock_cachep; >+extern struct key_type cifs_key_type; > > static int > cifs_read_super(struct super_block *sb, void *data, >@@ -1005,12 +1007,16 @@ init_cifs(void) > rc = register_filesystem(&cifs_fs_type); > if (rc) > goto out_destroy_request_bufs; >- >+#ifdef CONFIG_CIFS_UPCALL >+ rc = register_key_type(&cifs_key_type); >+ if (rc) >+ goto out_unregister_filesystem; >+#endif > oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd"); > if (IS_ERR(oplockThread)) { > rc = PTR_ERR(oplockThread); > cERROR(1, ("error %d create oplock thread", rc)); >- goto out_unregister_filesystem; >+ goto out_unregister_key_type; > } > > dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd"); >@@ -1024,7 +1030,11 @@ init_cifs(void) > > out_stop_oplock_thread: > kthread_stop(oplockThread); >+ out_unregister_key_type: >+#ifdef CONFIG_CIFS_UPCALL >+ unregister_key_type(&cifs_key_type); > out_unregister_filesystem: >+#endif > unregister_filesystem(&cifs_fs_type); > out_destroy_request_bufs: > cifs_destroy_request_bufs(); >@@ -1046,6 +1056,9 @@ exit_cifs(void) > #ifdef CONFIG_PROC_FS > cifs_proc_clean(); > #endif >+#ifdef CONFIG_CIFS_UPCALL >+ unregister_key_type(&cifs_key_type); >+#endif > unregister_filesystem(&cifs_fs_type); > cifs_destroy_inodecache(); > cifs_destroy_mids(); >diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h >index 87f51f2..7c30eb2 100644 >--- a/fs/cifs/cifsglob.h >+++ b/fs/cifs/cifsglob.h >@@ -622,4 +622,3 @@ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ > GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ > GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ > GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ >- >diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h >index 7c445f8..9fddf41 100644 >--- a/fs/cifs/cifsproto.h >+++ b/fs/cifs/cifsproto.h >@@ -73,9 +73,14 @@ extern void header_assemble(struct smb_hdr *, char /* command */ , > extern int small_smb_init_no_tc(const int smb_cmd, const int wct, > struct cifsSesInfo *ses, > void **request_buf); >+extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo, >+ const unsigned char *secblob, >+ size_t seclen, >+ const char *hostname); > extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, > const int stage, >- const struct nls_table *nls_cp); >+ const struct nls_table *nls_cp, >+ struct key *spnego_key); > extern __u16 GetNextMid(struct TCP_Server_Info *server); > extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16, > struct cifsTconInfo *); >@@ -100,8 +105,9 @@ void cifs_proc_init(void); > void cifs_proc_clean(void); > > extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, >- struct nls_table *nls_info); >-extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); >+ struct nls_table *nls_info, const char *unc); >+extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses, >+ struct key **spnego_key, const char *hostname); > > extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, > const char *tree, struct cifsTconInfo *tcon, >diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c >index f0d9a48..804159f 100644 >--- a/fs/cifs/cifssmb.c >+++ b/fs/cifs/cifssmb.c >@@ -38,6 +38,7 @@ > #include "cifsproto.h" > #include "cifs_unicode.h" > #include "cifs_debug.h" >+#include "cifsauth.h" > > #ifdef CONFIG_CIFS_POSIX > static struct { >@@ -157,7 +158,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, > down(&tcon->ses->sesSem); > if (tcon->ses->status == CifsNeedReconnect) > rc = cifs_setup_session(0, tcon->ses, >- nls_codepage); >+ nls_codepage, >+ tcon->treeName); > if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { > mark_open_files_invalid(tcon); > rc = CIFSTCon(0, tcon->ses, tcon->treeName, >@@ -302,7 +304,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, > down(&tcon->ses->sesSem); > if (tcon->ses->status == CifsNeedReconnect) > rc = cifs_setup_session(0, tcon->ses, >- nls_codepage); >+ nls_codepage, >+ tcon->treeName); > if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { > mark_open_files_invalid(tcon); > rc = CIFSTCon(0, tcon->ses, tcon->treeName, >@@ -405,7 +408,8 @@ static int validate_t2(struct smb_t2_rsp *pSMB) > return rc; > } > int >-CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) >+CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses, >+ struct key **spnego_key, const char *hostname) > { > NEGOTIATE_REQ *pSMB; > NEGOTIATE_RSP *pSMBr; >@@ -639,19 +643,36 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) > memcpy(server->server_GUID, > pSMBr->u.extended_response.GUID, 16); > >- if (count == 16) { >+ if (count == 16) > server->secType = RawNTLMSSP; >- } else { >- rc = decode_negTokenInit(pSMBr->u.extended_response. >- SecurityBlob, >- count - 16, >- &server->secType); >- if (rc == 1) { >- /* BB Need to fill struct for sessetup here */ >- rc = -EOPNOTSUPP; >- } else { >+ else { >+#ifdef CONFIG_CIFS_UPCALL >+ struct cifs_spnego_msg *msg; >+ *spnego_key = cifs_get_spnego_key(ses, pSMBr->u. >+ extended_response.SecurityBlob, >+ count - 16, hostname); >+ if (IS_ERR(*spnego_key)) { >+ rc = PTR_ERR(*spnego_key); >+ *spnego_key = NULL; >+ goto neg_err_exit; >+ } >+ >+ msg = (struct cifs_spnego_msg *) >+ (*spnego_key)->payload.data; >+ if (msg->flags & CIFS_AUTH_KRB5) >+ server->secType = Kerberos; >+ else if (msg->flags & CIFS_AUTH_NTLMSSP) >+ server->secType = NTLMSSP; >+ else { > rc = -EINVAL; >+ goto neg_err_exit; > } >+#else >+ cERROR(1("SPNEGO response received, but " >+ "CONFIG_CIFS_UPCALL not enabled!")); >+ rc = -EINVAL; >+ goto neg_err_exit; >+#endif > } > } else > server->capabilities &= ~CAP_EXTENDED_SECURITY; >diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c >index 19ee11f..f916b18 100644 >--- a/fs/cifs/connect.c >+++ b/fs/cifs/connect.c >@@ -1996,7 +1996,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > down(&pSesInfo->sesSem); > /* BB FIXME need to pass vol->secFlgs BB */ > rc = cifs_setup_session(xid, pSesInfo, >- cifs_sb->local_nls); >+ cifs_sb->local_nls, >+ volume_info.UNC); > up(&pSesInfo->sesSem); > if (!rc) > atomic_inc(&srvTcp->socketUseCount); >@@ -3508,19 +3509,57 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) > return rc; /* BB check if we should always return zero here */ > } > >+/* extract the host portion of the UNC string */ >+static char * >+extract_hostname_from_unc(const char *unc) >+{ >+ const char *src; >+ char *dst, *delim; >+ unsigned int len; >+ >+ /* skip double chars at beginning of string */ >+ /* BB: check validity of these bytes? */ >+ src = unc + 2; >+ >+ delim = strchr(src, '/'); >+ if (!delim) { >+ delim = strchr(src, '\\'); >+ if (!delim) >+ return ERR_PTR(-EINVAL); >+ } >+ >+ len = delim - src; >+ dst = kmalloc((len + 1), GFP_KERNEL); >+ if (dst == NULL) >+ return ERR_PTR(-ENOMEM); >+ >+ memcpy(dst, src, len); >+ dst[len] = '\0'; >+ >+ return dst; >+} >+ > int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, >- struct nls_table *nls_info) >+ struct nls_table *nls_info, const char *unc) > { > int rc = 0; > char ntlm_session_key[CIFS_SESS_KEY_SIZE]; > int ntlmv2_flag = FALSE; > int first_time = 0; >+ struct key *spnego_key = NULL; >+ char *hostname; >+ >+ hostname = extract_hostname_from_unc(unc); >+ if (IS_ERR(hostname)) { >+ rc = PTR_ERR(hostname); >+ hostname = NULL; >+ } > > /* what if server changes its buffer size after dropping the session? */ > if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { >- rc = CIFSSMBNegotiate(xid, pSesInfo); >+ rc = CIFSSMBNegotiate(xid, pSesInfo, &spnego_key, hostname); > if (rc == -EAGAIN) /* retry only once on 1st time connection */ { >- rc = CIFSSMBNegotiate(xid, pSesInfo); >+ rc = CIFSSMBNegotiate(xid, pSesInfo, &spnego_key, hostname); > if (rc == -EAGAIN) > rc = -EHOSTDOWN; > } >@@ -3548,7 +3587,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, > pSesInfo->server->timeAdj)); > if (experimEnabled < 2) > rc = CIFS_SessSetup(xid, pSesInfo, >- first_time, nls_info); >+ first_time, nls_info, spnego_key); > else if (extended_security > && (pSesInfo->capabilities > & CAP_EXTENDED_SECURITY) >@@ -3627,6 +3666,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, > } > } > ss_err_exit: >+ if (spnego_key) >+ key_put(spnego_key); >+ if (hostname) >+ kfree(hostname); >+ > return rc; > } > >diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c >index 899dc60..2a55308 100644 >--- a/fs/cifs/sess.c >+++ b/fs/cifs/sess.c >@@ -29,6 +29,7 @@ > #include "ntlmssp.h" > #include "nterr.h" > #include <linux/utsname.h> >+#include "cifsauth.h" > > extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, > unsigned char *p24); >@@ -330,7 +331,7 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, > > int > CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, >- const struct nls_table *nls_cp) >+ const struct nls_table *nls_cp, struct key *spnego_key) > { > int rc = 0; > int wct; >@@ -341,7 +342,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, > __u32 capabilities; > int count; > int resp_buf_type = 0; >- struct kvec iov[2]; >+ struct kvec iov[3]; > enum securityEnum type; > __u16 action; > int bytes_remaining; >@@ -395,6 +396,9 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, > > ses->flags &= ~CIFS_SES_LANMAN; > >+ iov[1].iov_base = NULL; >+ iov[1].iov_len = 0; >+ > if (type == LANMAN) { > #ifdef CONFIG_CIFS_WEAK_PW_HASH > char lnm_session_key[CIFS_SESS_KEY_SIZE]; >@@ -499,21 +503,42 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, > unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); > } else > ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); >- } else /* NTLMSSP or SPNEGO */ { >+#ifdef CONFIG_CIFS_UPCALL >+ } else if (type == Kerberos) { >+ struct cifs_spnego_msg *msg = spnego_key->payload.data; >+ ses->server->mac_signing_key.len = msg->sesskey_len; >+ memcpy(ses->server->mac_signing_key.data.ntlm, msg->data, >+ msg->sesskey_len); > pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; > capabilities |= CAP_EXTENDED_SECURITY; > pSMB->req.Capabilities = cpu_to_le32(capabilities); >- /* BB set password lengths */ >+ iov[1].iov_base = msg->data + msg->sesskey_len; >+ iov[1].iov_len = msg->secblob_len; >+ pSMB->req.SecurityBlobLength = cpu_to_le16(iov[1].iov_len); >+ >+ if (ses->capabilities & CAP_UNICODE) { >+ /* unicode strings must be word aligned */ >+ if (iov[0].iov_len % 2) { >+ *bcc_ptr = 0; >+ bcc_ptr++; >+ } >+ unicode_oslm_strings(&bcc_ptr, nls_cp); >+ unicode_domain_string(&bcc_ptr, ses, nls_cp); >+ } else >+ /* BB: is this right? */ >+ ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); >+#endif > } > >- count = (long) bcc_ptr - (long) str_area; >+ iov[2].iov_base = str_area; >+ iov[2].iov_len = (long) bcc_ptr - (long) str_area; >+ >+ count = iov[1].iov_len + iov[2].iov_len; > smb_buf->smb_buf_length += count; > > BCC_LE(smb_buf) = cpu_to_le16(count); > >- iov[1].iov_base = str_area; >- iov[1].iov_len = count; >- rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, >+ rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, > 0 /* not long op */, 1 /* log NT STATUS if any */ ); > /* SMB request buf freed in SendReceive2 */ > >diff --git a/include/linux/key.h b/include/linux/key.h >index fcdbd5e..4a6021a 100644 >--- a/include/linux/key.h >+++ b/include/linux/key.h >@@ -208,16 +208,19 @@ extern struct key *request_key(struct key_type *type, > > extern struct key *request_key_with_auxdata(struct key_type *type, > const char *description, >- const char *callout_info, >+ const void *callout_info, >+ size_t callout_len, > void *aux); > > extern struct key *request_key_async(struct key_type *type, > const char *description, >- const char *callout_info); >+ const void *callout_info, >+ size_t callout_len); > > extern struct key *request_key_async_with_auxdata(struct key_type *type, > const char *description, >- const char *callout_info, >+ const void *callout_info, >+ size_t callout_len, > void *aux); > > extern int wait_for_key_construction(struct key *key, bool intr); >diff --git a/security/keys/internal.h b/security/keys/internal.h >index d36d693..f004835 100644 >--- a/security/keys/internal.h >+++ b/security/keys/internal.h >@@ -109,7 +109,8 @@ extern int install_process_keyring(struct task_struct *tsk); > > extern struct key *request_key_and_link(struct key_type *type, > const char *description, >- const char *callout_info, >+ const void *callout_info, >+ size_t callout_len, > void *aux, > struct key *dest_keyring, > unsigned long flags); >@@ -120,13 +121,15 @@ extern struct key *request_key_and_link(struct key_type *type, > struct request_key_auth { > struct key *target_key; > struct task_struct *context; >- char *callout_info; >+ void *callout_info; >+ size_t callout_len; > pid_t pid; > }; > > extern struct key_type key_type_request_key_auth; > extern struct key *request_key_auth_new(struct key *target, >- const char *callout_info); >+ const void *callout_info, >+ size_t callout_len); > > extern struct key *key_get_instantiation_authkey(key_serial_t target_id); > >diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c >index d9ca15c..1698bf9 100644 >--- a/security/keys/keyctl.c >+++ b/security/keys/keyctl.c >@@ -19,6 +19,7 @@ > #include <linux/capability.h> > #include <linux/string.h> > #include <linux/err.h> >+#include <linux/vmalloc.h> > #include <asm/uaccess.h> > #include "internal.h" > >@@ -62,9 +63,10 @@ asmlinkage long sys_add_key(const char __user *_type, > char type[32], *description; > void *payload; > long ret; >+ bool vm; > > ret = -EINVAL; >- if (plen > 32767) >+ if (plen > 1024 * 1024 - 1) > goto error; > > /* draw all the data into kernel space */ >@@ -81,11 +83,18 @@ asmlinkage long sys_add_key(const char __user *_type, > /* pull the payload in if one was supplied */ > payload = NULL; > >+ vm = false; > if (_payload) { > ret = -ENOMEM; > payload = kmalloc(plen, GFP_KERNEL); >- if (!payload) >- goto error2; >+ if (!payload) { >+ if (plen <= PAGE_SIZE) >+ goto error2; >+ vm = true; >+ payload = vmalloc(plen); >+ if (!payload) >+ goto error2; >+ } > > ret = -EFAULT; > if (copy_from_user(payload, _payload, plen) != 0) >@@ -113,7 +122,10 @@ asmlinkage long sys_add_key(const char __user *_type, > > key_ref_put(keyring_ref); > error3: >- kfree(payload); >+ if (!vm) >+ kfree(payload); >+ else >+ vfree(payload); > error2: > kfree(description); > error: >@@ -140,6 +152,7 @@ asmlinkage long sys_request_key(const char __user *_type, > struct key_type *ktype; > struct key *key; > key_ref_t dest_ref; >+ size_t callout_len; > char type[32], *description, *callout_info; > long ret; > >@@ -157,12 +170,14 @@ asmlinkage long sys_request_key(const char __user *_type, > > /* pull the callout info into kernel space */ > callout_info = NULL; >+ callout_len = 0; > if (_callout_info) { > callout_info = strndup_user(_callout_info, PAGE_SIZE); > if (IS_ERR(callout_info)) { > ret = PTR_ERR(callout_info); > goto error2; > } >+ callout_len = strlen(callout_info); > } > > /* get the destination keyring if specified */ >@@ -183,8 +198,8 @@ asmlinkage long sys_request_key(const char __user *_type, > } > > /* do the search */ >- key = request_key_and_link(ktype, description, callout_info, NULL, >- key_ref_to_ptr(dest_ref), >+ key = request_key_and_link(ktype, description, callout_info, >+ callout_len, NULL, key_ref_to_ptr(dest_ref), > KEY_ALLOC_IN_QUOTA); > if (IS_ERR(key)) { > ret = PTR_ERR(key); >@@ -821,9 +836,10 @@ long keyctl_instantiate_key(key_serial_t id, > key_ref_t keyring_ref; > void *payload; > long ret; >+ bool vm = false; > > ret = -EINVAL; >- if (plen > 32767) >+ if (plen > 1024 * 1024 - 1) > goto error; > > /* the appropriate instantiation authorisation key must have been >@@ -843,8 +859,14 @@ long keyctl_instantiate_key(key_serial_t id, > if (_payload) { > ret = -ENOMEM; > payload = kmalloc(plen, GFP_KERNEL); >- if (!payload) >- goto error; >+ if (!payload) { >+ if (plen <= PAGE_SIZE) >+ goto error; >+ vm = true; >+ payload = vmalloc(plen); >+ if (!payload) >+ goto error; >+ } > > ret = -EFAULT; > if (copy_from_user(payload, _payload, plen) != 0) >@@ -877,7 +899,10 @@ long keyctl_instantiate_key(key_serial_t id, > } > > error2: >- kfree(payload); >+ if (!vm) >+ kfree(payload); >+ else >+ vfree(payload); > error: > return ret; > >diff --git a/security/keys/keyring.c b/security/keys/keyring.c >index 88292e3..76b89b2 100644 >--- a/security/keys/keyring.c >+++ b/security/keys/keyring.c >@@ -292,7 +292,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, > > struct keyring_list *keylist; > struct timespec now; >- unsigned long possessed; >+ unsigned long possessed, kflags; > struct key *keyring, *key; > key_ref_t key_ref; > long err; >@@ -318,6 +318,32 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, > now = current_kernel_time(); > err = -EAGAIN; > sp = 0; >+ >+ /* firstly we should check to see if this top-level keyring is what we >+ * are looking for */ >+ key_ref = ERR_PTR(-EAGAIN); >+ kflags = keyring->flags; >+ if (keyring->type == type && match(keyring, description)) { >+ key = keyring; >+ >+ /* check it isn't negative and hasn't expired or been >+ * revoked */ >+ if (kflags & (1 << KEY_FLAG_REVOKED)) >+ goto error_2; >+ if (key->expiry && now.tv_sec >= key->expiry) >+ goto error_2; >+ key_ref = ERR_PTR(-ENOKEY); >+ if (kflags & (1 << KEY_FLAG_NEGATIVE)) >+ goto error_2; >+ goto found; >+ } >+ >+ /* otherwise, the top keyring must not be revoked, expired, or >+ * negatively instantiated if we are to search it */ >+ key_ref = ERR_PTR(-EAGAIN); >+ if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || >+ (keyring->expiry && now.tv_sec >= keyring->expiry)) >+ goto error_2; > > /* start processing a new keyring */ > descend: >@@ -331,13 +357,14 @@ descend: > /* iterate through the keys in this keyring first */ > for (kix = 0; kix < keylist->nkeys; kix++) { > key = keylist->keys[kix]; >+ kflags = key->flags; > > /* ignore keys not of this type */ > if (key->type != type) > continue; > > /* skip revoked keys and expired keys */ >- if (test_bit(KEY_FLAG_REVOKED, &key->flags)) >+ if (kflags & (1 << KEY_FLAG_REVOKED)) > continue; > > if (key->expiry && now.tv_sec >= key->expiry) >@@ -352,8 +379,8 @@ descend: > context, KEY_SEARCH) < 0) > continue; > >- /* we set a different error code if we find a negative key */ >- if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { >+ /* we set a different error code if we pass a negative key */ >+ if (kflags & (1 << KEY_FLAG_NEGATIVE)) { > err = -ENOKEY; > continue; > } >diff --git a/security/keys/request_key.c b/security/keys/request_key.c >index 6381e61..2605f01 100644 >--- a/security/keys/request_key.c >+++ b/security/keys/request_key.c >@@ -161,21 +161,22 @@ error_alloc: > * call out to userspace for key construction > * - we ignore program failure and go on key status instead > */ >-static int construct_key(struct key *key, const char *callout_info, void *aux) >+static int construct_key(struct key *key, const void *callout_info, >+ size_t callout_len, void *aux) > { > struct key_construction *cons; > request_key_actor_t actor; > struct key *authkey; > int ret; > >- kenter("%d,%s,%p", key->serial, callout_info, aux); >+ kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux); > > cons = kmalloc(sizeof(*cons), GFP_KERNEL); > if (!cons) > return -ENOMEM; > > /* allocate an authorisation key */ >- authkey = request_key_auth_new(key, callout_info); >+ authkey = request_key_auth_new(key, callout_info, callout_len); > if (IS_ERR(authkey)) { > kfree(cons); > ret = PTR_ERR(authkey); >@@ -331,6 +332,7 @@ alloc_failed: > static struct key *construct_key_and_link(struct key_type *type, > const char *description, > const char *callout_info, >+ size_t callout_len, > void *aux, > struct key *dest_keyring, > unsigned long flags) >@@ -348,7 +350,7 @@ static struct key *construct_key_and_link(struct key_type *type, > key_user_put(user); > > if (ret == 0) { >- ret = construct_key(key, callout_info, aux); >+ ret = construct_key(key, callout_info, callout_len, aux); > if (ret < 0) > goto construction_failed; > } >@@ -370,7 +372,8 @@ construction_failed: > */ > struct key *request_key_and_link(struct key_type *type, > const char *description, >- const char *callout_info, >+ const void *callout_info, >+ size_t callout_len, > void *aux, > struct key *dest_keyring, > unsigned long flags) >@@ -378,8 +381,8 @@ struct key *request_key_and_link(struct key_type *type, > struct key *key; > key_ref_t key_ref; > >- kenter("%s,%s,%s,%p,%p,%lx", >- type->name, description, callout_info, aux, >+ kenter("%s,%s,%p,%zu,%p,%p,%lx", >+ type->name, description, callout_info, callout_len, aux, > dest_keyring, flags); > > /* search all the process keyrings for a key */ >@@ -398,7 +401,8 @@ struct key *request_key_and_link(struct key_type *type, > goto error; > > key = construct_key_and_link(type, description, callout_info, >- aux, dest_keyring, flags); >+ callout_len, aux, dest_keyring, >+ flags); > } > > error: >@@ -436,7 +440,8 @@ struct key *request_key(struct key_type *type, > struct key *key; > int ret; > >- key = request_key_and_link(type, description, callout_info, NULL, >+ key = request_key_and_link(type, description, callout_info, >+ strlen(callout_info), NULL, > NULL, KEY_ALLOC_IN_QUOTA); > if (!IS_ERR(key)) { > ret = wait_for_key_construction(key, false); >@@ -458,14 +463,15 @@ EXPORT_SYMBOL(request_key); > */ > struct key *request_key_with_auxdata(struct key_type *type, > const char *description, >- const char *callout_info, >+ const void *callout_info, >+ size_t callout_len, > void *aux) > { > struct key *key; > int ret; > >- key = request_key_and_link(type, description, callout_info, aux, >- NULL, KEY_ALLOC_IN_QUOTA); >+ key = request_key_and_link(type, description, callout_info, callout_len, >+ aux, NULL, KEY_ALLOC_IN_QUOTA); > if (!IS_ERR(key)) { > ret = wait_for_key_construction(key, false); > if (ret < 0) { >@@ -485,10 +491,12 @@ EXPORT_SYMBOL(request_key_with_auxdata); > */ > struct key *request_key_async(struct key_type *type, > const char *description, >- const char *callout_info) >+ const void *callout_info, >+ size_t callout_len) > { >- return request_key_and_link(type, description, callout_info, NULL, >- NULL, KEY_ALLOC_IN_QUOTA); >+ return request_key_and_link(type, description, callout_info, >+ callout_len, NULL, NULL, >+ KEY_ALLOC_IN_QUOTA); > } > EXPORT_SYMBOL(request_key_async); > >@@ -500,10 +508,11 @@ EXPORT_SYMBOL(request_key_async); > */ > struct key *request_key_async_with_auxdata(struct key_type *type, > const char *description, >- const char *callout_info, >+ const void *callout_info, >+ size_t callout_len, > void *aux) > { >- return request_key_and_link(type, description, callout_info, aux, >- NULL, KEY_ALLOC_IN_QUOTA); >+ return request_key_and_link(type, description, callout_info, >+ callout_len, aux, NULL, KEY_ALLOC_IN_QUOTA); > } > EXPORT_SYMBOL(request_key_async_with_auxdata); >diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c >index 510f7be..6827ae3 100644 >--- a/security/keys/request_key_auth.c >+++ b/security/keys/request_key_auth.c >@@ -61,7 +61,7 @@ static void request_key_auth_describe(const struct key *key, > > seq_puts(m, "key:"); > seq_puts(m, key->description); >- seq_printf(m, " pid:%d ci:%zu", rka->pid, strlen(rka->callout_info)); >+ seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); > > } /* end request_key_auth_describe() */ > >@@ -77,7 +77,7 @@ static long request_key_auth_read(const struct key *key, > size_t datalen; > long ret; > >- datalen = strlen(rka->callout_info); >+ datalen = rka->callout_len; > ret = datalen; > > /* we can return the data as is */ >@@ -137,7 +137,8 @@ static void request_key_auth_destroy(struct key *key) > * create an authorisation token for /sbin/request-key or whoever to gain > * access to the caller's security data > */ >-struct key *request_key_auth_new(struct key *target, const char *callout_info) >+struct key *request_key_auth_new(struct key *target, const void *callout_info, >+ size_t callout_len) > { > struct request_key_auth *rka, *irka; > struct key *authkey = NULL; >@@ -152,7 +153,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) > kleave(" = -ENOMEM"); > return ERR_PTR(-ENOMEM); > } >- rka->callout_info = kmalloc(strlen(callout_info) + 1, GFP_KERNEL); >+ rka->callout_info = kmalloc(callout_len, GFP_KERNEL); > if (!rka->callout_info) { > kleave(" = -ENOMEM"); > kfree(rka); >@@ -186,7 +187,8 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) > } > > rka->target_key = key_get(target); >- strcpy(rka->callout_info, callout_info); >+ memcpy(rka->callout_info, callout_info, callout_len); >+ rka->callout_len = callout_len; > > /* allocate the auth key */ > sprintf(desc, "%x", target->serial);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 315311
:
215841
|
217871
|
218261
|
218271
|
228611
|
232741
|
236521
|
237721
|
248401