Re: [PATCH 3/3] cifs: fetch credentials out of keyring for non-krb5 auth multiuser mounts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 6 Jan 2012 11:16:32 -0600
Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx> wrote:

> On Fri, Jan 6, 2012 at 7:11 AM, Jeff Layton <jlayton@xxxxxxxxxx> wrote:
> > Fix up multiuser mounts to set the secType and set the username and
> > password from the key payload in the vol info for non-krb5 auth types.
> >
> > Look for a key of type "secret" with a description of
> > "cifs:a:<server address>" or "cifs:d:<domainname>". If that's found,
> > then scrape the username and password out of the key payload and use
> > that to create a new user session.
> >
> > Finally, don't have the code enforce krb5 auth on multiuser mounts,
> > but do require a kernel with keys support.
> >
> > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> > ---
> >  fs/cifs/connect.c |  176 ++++++++++++++++++++++++++++++++++++++++++++++++++---
> >  1 files changed, 166 insertions(+), 10 deletions(-)
> >
> > diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> > index 5e96e60..48f2d15 100644
> > --- a/fs/cifs/connect.c
> > +++ b/fs/cifs/connect.c
> > @@ -38,6 +38,7 @@
> >  #include <asm/processor.h>
> >  #include <linux/inet.h>
> >  #include <linux/module.h>
> > +#include <keys/user-type.h>
> >  #include <net/ipv6.h>
> >  #include "cifspdu.h"
> >  #include "cifsglob.h"
> > @@ -1594,11 +1595,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
> >                }
> >        }
> >
> > -       if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) {
> > -               cERROR(1, "Multiuser mounts currently require krb5 "
> > -                         "authentication!");
> > +#ifndef CONFIG_KEYS
> > +       /* Muliuser mounts require CONFIG_KEYS support */
> > +       if (vol->multiuser) {
> > +               cERROR(1, "Multiuser mounts require kernels with "
> > +                         "CONFIG_KEYS enabled.");
> >                goto cifs_parse_mount_err;
> >        }
> > +#endif
> 
> Will this break existing setups when those users update kernel
> and/or update cifs module?
> 

No. Why would it? You need keys support for krb5 auth.

> >
> >        if (vol->UNCip == NULL)
> >                vol->UNCip = &vol->UNC[2];
> > @@ -2061,6 +2065,133 @@ cifs_put_smb_ses(struct cifs_ses *ses)
> >        cifs_put_tcp_session(server);
> >  }
> >
> > +#ifdef CONFIG_KEYS
> > +
> > +/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */
> > +#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1)
> > +
> > +/* Populate username and pw fields from keyring if possible */
> > +static int
> > +cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
> > +{
> > +       int rc = 0;
> > +       char *desc, *delim, *payload;
> > +       ssize_t len;
> > +       struct key *key;
> > +       struct TCP_Server_Info *server = ses->server;
> > +       struct sockaddr_in *sa;
> > +       struct sockaddr_in6 *sa6;
> > +       struct user_key_payload *upayload;
> > +
> > +       desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
> > +       if (!desc)
> > +               return -ENOMEM;
> > +
> > +       /* try to find an address key first */
> > +       switch (server->dstaddr.ss_family) {
> > +       case AF_INET:
> > +               sa = (struct sockaddr_in *)&server->dstaddr;
> > +               sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
> > +               break;
> > +       case AF_INET6:
> > +               sa6 = (struct sockaddr_in6 *)&server->dstaddr;
> > +               sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
> > +               break;
> > +       default:
> > +               cFYI(1, "Bad ss_family (%hu)", server->dstaddr.ss_family);
> > +               rc = -EINVAL;
> > +               goto out_err;
> > +       }
> > +
> > +       cFYI(1, "%s: desc=%s", __func__, desc);
> > +       key = request_key(&key_type_secret, desc, "");
> > +       if (IS_ERR(key)) {
> > +               if (!ses->domainName) {
> > +                       cFYI(1, "domainName is NULL");
> > +                       rc = PTR_ERR(key);
> > +                       goto out_err;
> > +               }
> > +
> > +               /* didn't work, try to find a domain key */
> > +               sprintf(desc, "cifs:d:%s", ses->domainName);
> > +               cFYI(1, "%s: desc=%s", __func__, desc);
> > +               key = request_key(&key_type_secret, desc, "");
> > +               if (IS_ERR(key)) {
> > +                       rc = PTR_ERR(key);
> > +                       goto out_err;
> > +               }
> > +       }
> > +
> > +       down_read(&key->sem);
> > +       upayload = key->payload.data;
> > +       if (IS_ERR_OR_NULL(upayload)) {
> > +               rc = PTR_ERR(key);
> > +               goto out_key_put;
> > +       }
> > +
> > +       /* find first : in payload */
> > +       payload = (char *)upayload->data;
> > +       delim = strnchr(payload, upayload->datalen, ':');
> > +       cFYI(1, "payload=%s", payload);
> > +       if (!delim) {
> > +               cFYI(1, "Unable to find ':' in payload (datalen=%d)",
> > +                               upayload->datalen);
> > +               rc = -EINVAL;
> > +               goto out_key_put;
> > +       }
> > +
> > +       len = delim - payload;
> > +       if (len > MAX_USERNAME_SIZE || len <= 0) {
> > +               cFYI(1, "Bad value from username search (len=%ld)", len);
> > +               rc = -EINVAL;
> > +               goto out_key_put;
> > +       }
> > +
> > +       vol->username = kstrndup(payload, len, GFP_KERNEL);
> > +       if (!vol->username) {
> > +               cFYI(1, "Unable to allocate %ld bytes for username", len);
> > +               rc = -ENOMEM;
> > +               goto out_key_put;
> > +       }
> > +       cFYI(1, "username=%s", vol->username);
> > +
> > +       len = key->datalen - (len + 1);
> > +       if (len > MAX_PASSWORD_SIZE || len <= 0) {
> > +               cFYI(1, "Bad len for password search (len=%ld)", len);
> > +               rc = -EINVAL;
> > +               kfree(vol->username);
> > +               vol->username = NULL;
> > +               goto out_key_put;
> > +       }
> > +
> > +       ++delim;
> > +       vol->password = kstrndup(delim, len, GFP_KERNEL);
> > +       if (!vol->password) {
> > +               cFYI(1, "Unable to allocate %ld bytes for password", len);
> > +               rc = -ENOMEM;
> > +               kfree(vol->username);
> > +               vol->username = NULL;
> > +               goto out_key_put;
> > +       }
> > +       cFYI(1, "password=%s", vol->password);
> 
> I would be wary of printing the password.
> 

Good point. I had that in there when I was debugging this, but I think
I can remove it now.

> > +
> > +out_key_put:
> > +       up_read(&key->sem);
> > +       key_put(key);
> > +out_err:
> > +       kfree(desc);
> > +       cFYI(1, "%s: returning %d", __func__, rc);
> > +       return rc;
> > +}
> > +#else /* ! CONFIG_KEYS */
> > +static inline int
> > +cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)),
> > +                  struct cifs_ses *ses __attribute__((unused)))
> > +{
> > +       return -ENOSYS;
> > +}
> > +#endif /* CONFIG_KEYS */
> > +
> >  static bool warned_on_ntlm;  /* globals init to false automatically */
> >
> >  static struct cifs_ses *
> > @@ -3678,16 +3809,38 @@ int cifs_setup_session(unsigned int xid, struct cifs_ses *ses,
> >        return rc;
> >  }
> >
> > +static int
> > +cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)
> > +{
> > +       switch(ses->server->secType) {
> > +       case Kerberos:
> > +               vol->secFlg = CIFSSEC_MUST_KRB5;
> > +               return 0;
> > +       case NTLMv2:
> > +               vol->secFlg = CIFSSEC_MUST_NTLMV2;
> > +               break;
> > +       case NTLM:
> > +               vol->secFlg = CIFSSEC_MUST_NTLM;
> > +               break;
> > +       case RawNTLMSSP:
> > +               vol->secFlg = CIFSSEC_MAY_NTLMSSP;
> > +               break;
> > +       case LANMAN:
> > +               vol->secFlg = CIFSSEC_MAY_LANMAN;
> > +               break;
> > +       }

Also, since we're critiquing this patch, the MAYs above should probably
be MUSTs.

> > +
> > +       return cifs_set_cifscreds(vol, ses);
> > +}
> > +
> >  static struct cifs_tcon *
> >  cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
> >  {
> > +       int rc;
> >        struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
> >        struct cifs_ses *ses;
> >        struct cifs_tcon *tcon = NULL;
> >        struct smb_vol *vol_info;
> > -       char username[28]; /* big enough for "krb50x" + hex of ULONG_MAX 6+16 */
> > -                          /* We used to have this as MAX_USERNAME which is   */
> > -                          /* way too big now (256 instead of 32) */
> >
> >        vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
> >        if (vol_info == NULL) {
> > @@ -3695,8 +3848,6 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
> >                goto out;
> >        }
> >
> > -       snprintf(username, sizeof(username), "krb50x%x", fsuid);
> > -       vol_info->username = username;
> >        vol_info->local_nls = cifs_sb->local_nls;
> >        vol_info->linux_uid = fsuid;
> >        vol_info->cred_uid = fsuid;
> > @@ -3706,8 +3857,11 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
> >        vol_info->local_lease = master_tcon->local_lease;
> >        vol_info->no_linux_ext = !master_tcon->unix_ext;
> >
> > -       /* FIXME: allow for other secFlg settings */
> > -       vol_info->secFlg = CIFSSEC_MUST_KRB5;
> > +       rc = cifs_set_vol_auth(vol_info, master_tcon->ses);
> > +       if (rc) {
> > +               tcon = ERR_PTR(rc);
> > +               goto out;
> > +       }
> >
> >        /* get a reference for the same TCP session */
> >        spin_lock(&cifs_tcp_ses_lock);
> > @@ -3730,6 +3884,8 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
> >        if (ses->capabilities & CAP_UNIX)
> >                reset_cifs_unix_caps(0, tcon, NULL, vol_info);
> >  out:
> > +       kfree(vol_info->username);
> > +       kfree(vol_info->password);
> >        kfree(vol_info);
> >
> >        return tcon;
> > --
> > 1.7.7.4
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> > the body of a message to majordomo@xxxxxxxxxxxxxxx
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html


-- 
Jeff Layton <jlayton@xxxxxxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux