2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* linux/include/linux/sunrpc/auth.h
|
|
|
|
*
|
|
|
|
* Declarations for the RPC client authentication machinery.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _LINUX_SUNRPC_AUTH_H
|
|
|
|
#define _LINUX_SUNRPC_AUTH_H
|
|
|
|
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
|
|
|
|
#include <linux/sunrpc/sched.h>
|
|
|
|
#include <linux/sunrpc/msg_prot.h>
|
|
|
|
#include <linux/sunrpc/xdr.h>
|
|
|
|
|
2011-07-27 06:09:06 +07:00
|
|
|
#include <linux/atomic.h>
|
2007-06-25 02:55:26 +07:00
|
|
|
#include <linux/rcupdate.h>
|
2013-02-02 07:31:17 +07:00
|
|
|
#include <linux/uidgid.h>
|
2015-08-03 18:44:53 +07:00
|
|
|
#include <linux/utsname.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2016-03-02 01:06:02 +07:00
|
|
|
/*
|
|
|
|
* Maximum size of AUTH_NONE authentication information, in XDR words.
|
|
|
|
*/
|
|
|
|
#define NUL_CALLSLACK (4)
|
|
|
|
#define NUL_REPLYSLACK (2)
|
|
|
|
|
2015-08-03 18:44:53 +07:00
|
|
|
/*
|
|
|
|
* Size of the nodename buffer. RFC1831 specifies a hard limit of 255 bytes,
|
|
|
|
* but Linux hostnames are actually limited to __NEW_UTS_LEN bytes.
|
|
|
|
*/
|
|
|
|
#define UNX_MAXNODENAME __NEW_UTS_LEN
|
2016-03-02 01:06:02 +07:00
|
|
|
#define UNX_CALLSLACK (21 + XDR_QUADLEN(UNX_MAXNODENAME))
|
2017-02-07 20:48:11 +07:00
|
|
|
#define UNX_NGROUPS 16
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2013-03-17 02:54:43 +07:00
|
|
|
struct rpcsec_gss_info;
|
|
|
|
|
2013-08-14 22:59:15 +07:00
|
|
|
/* auth_cred ac_flags bits */
|
|
|
|
enum {
|
|
|
|
RPC_CRED_KEY_EXPIRE_SOON = 1, /* underlying cred key will expire soon */
|
|
|
|
RPC_CRED_NOTIFY_TIMEOUT = 2, /* nofity generic cred when underlying
|
|
|
|
key will expire soon */
|
|
|
|
};
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Work around the lack of a VFS credential */
|
|
|
|
struct auth_cred {
|
2013-02-02 07:31:17 +07:00
|
|
|
kuid_t uid;
|
|
|
|
kgid_t gid;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct group_info *group_info;
|
2012-01-04 01:22:46 +07:00
|
|
|
const char *principal;
|
2013-08-14 22:59:15 +07:00
|
|
|
unsigned long ac_flags;
|
2008-04-08 07:50:11 +07:00
|
|
|
unsigned char machine_cred : 1;
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Client user credentials
|
|
|
|
*/
|
2007-06-07 21:14:14 +07:00
|
|
|
struct rpc_auth;
|
|
|
|
struct rpc_credops;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct rpc_cred {
|
|
|
|
struct hlist_node cr_hash; /* hash chain */
|
2007-06-24 06:45:36 +07:00
|
|
|
struct list_head cr_lru; /* lru garbage collection */
|
2007-06-25 02:55:26 +07:00
|
|
|
struct rcu_head cr_rcu;
|
2007-06-07 21:14:14 +07:00
|
|
|
struct rpc_auth * cr_auth;
|
2007-06-24 07:17:58 +07:00
|
|
|
const struct rpc_credops *cr_ops;
|
2007-06-25 21:15:15 +07:00
|
|
|
unsigned long cr_expire; /* when to gc */
|
|
|
|
unsigned long cr_flags; /* various flags */
|
|
|
|
atomic_t cr_count; /* ref count */
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2013-02-02 07:31:17 +07:00
|
|
|
kuid_t cr_uid;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* per-flavor data */
|
|
|
|
};
|
2007-06-25 21:15:15 +07:00
|
|
|
#define RPCAUTH_CRED_NEW 0
|
|
|
|
#define RPCAUTH_CRED_UPTODATE 1
|
2007-06-25 02:55:26 +07:00
|
|
|
#define RPCAUTH_CRED_HASHED 2
|
2010-05-13 23:55:38 +07:00
|
|
|
#define RPCAUTH_CRED_NEGATIVE 3
|
2005-04-17 05:20:36 +07:00
|
|
|
|
sunrpc: move NO_CRKEY_TIMEOUT to the auth->au_flags
A generic_cred can be used to look up a unx_cred or a gss_cred, so it's
not really safe to use the the generic_cred->acred->ac_flags to store
the NO_CRKEY_TIMEOUT flag. A lookup for a unx_cred triggered while the
KEY_EXPIRE_SOON flag is already set will cause both NO_CRKEY_TIMEOUT and
KEY_EXPIRE_SOON to be set in the ac_flags, leaving the user associated
with the auth_cred to be in a state where they're perpetually doing 4K
NFS_FILE_SYNC writes.
This can be reproduced as follows:
1. Mount two NFS filesystems, one with sec=krb5 and one with sec=sys.
They do not need to be the same export, nor do they even need to be from
the same NFS server. Also, v3 is fine.
$ sudo mount -o v3,sec=krb5 server1:/export /mnt/krb5
$ sudo mount -o v3,sec=sys server2:/export /mnt/sys
2. As the normal user, before accessing the kerberized mount, kinit with
a short lifetime (but not so short that renewing the ticket would leave
you within the 4-minute window again by the time the original ticket
expires), e.g.
$ kinit -l 10m -r 60m
3. Do some I/O to the kerberized mount and verify that the writes are
wsize, UNSTABLE:
$ dd if=/dev/zero of=/mnt/krb5/file bs=1M count=1
4. Wait until you're within 4 minutes of key expiry, then do some more
I/O to the kerberized mount to ensure that RPC_CRED_KEY_EXPIRE_SOON gets
set. Verify that the writes are 4K, FILE_SYNC:
$ dd if=/dev/zero of=/mnt/krb5/file bs=1M count=1
5. Now do some I/O to the sec=sys mount. This will cause
RPC_CRED_NO_CRKEY_TIMEOUT to be set:
$ dd if=/dev/zero of=/mnt/sys/file bs=1M count=1
6. Writes for that user will now be permanently 4K, FILE_SYNC for that
user, regardless of which mount is being written to, until you reboot
the client. Renewing the kerberos ticket (assuming it hasn't already
expired) will have no effect. Grabbing a new kerberos ticket at this
point will have no effect either.
Move the flag to the auth->au_flags field (which is currently unused)
and rename it slightly to reflect that it's no longer associated with
the auth_cred->ac_flags. Add the rpc_auth to the arg list of
rpcauth_cred_key_to_expire and check the au_flags there too. Finally,
add the inode to the arg list of nfs_ctx_key_to_expire so we can
determine the rpc_auth to pass to rpcauth_cred_key_to_expire.
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
2016-06-08 02:14:48 +07:00
|
|
|
/* rpc_auth au_flags */
|
|
|
|
#define RPCAUTH_AUTH_NO_CRKEY_TIMEOUT 0x0001 /* underlying cred has no key timeout */
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* Client authentication handle
|
|
|
|
*/
|
2010-08-01 01:29:08 +07:00
|
|
|
struct rpc_cred_cache;
|
2007-06-07 21:14:14 +07:00
|
|
|
struct rpc_authops;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct rpc_auth {
|
|
|
|
unsigned int au_cslack; /* call cred size estimate */
|
2005-10-14 03:54:53 +07:00
|
|
|
/* guess at number of u32's auth adds before
|
|
|
|
* reply data; normally the verifier size: */
|
|
|
|
unsigned int au_rslack;
|
|
|
|
/* for gss, used to calculate au_rslack: */
|
|
|
|
unsigned int au_verfsize;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
unsigned int au_flags; /* various flags */
|
2007-06-24 07:17:58 +07:00
|
|
|
const struct rpc_authops *au_ops; /* operations */
|
2005-04-17 05:20:36 +07:00
|
|
|
rpc_authflavor_t au_flavor; /* pseudoflavor (note may
|
|
|
|
* differ from the flavor in
|
|
|
|
* au_ops->au_flavor in gss
|
|
|
|
* case) */
|
|
|
|
atomic_t au_count; /* Reference counter */
|
|
|
|
|
|
|
|
struct rpc_cred_cache * au_credcache;
|
|
|
|
/* per-flavor data */
|
|
|
|
};
|
|
|
|
|
2016-06-30 00:55:06 +07:00
|
|
|
/* rpc_auth au_flags */
|
|
|
|
#define RPCAUTH_AUTH_DATATOUCH 0x00000002
|
|
|
|
|
2013-08-27 06:23:04 +07:00
|
|
|
struct rpc_auth_create_args {
|
|
|
|
rpc_authflavor_t pseudoflavor;
|
|
|
|
const char *target_name;
|
|
|
|
};
|
|
|
|
|
2006-02-02 00:18:36 +07:00
|
|
|
/* Flags for rpcauth_lookupcred() */
|
|
|
|
#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */
|
2014-07-14 08:28:20 +07:00
|
|
|
#define RPCAUTH_LOOKUP_RCU 0x02 /* lock-less lookup */
|
2006-02-02 00:18:36 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* Client authentication ops
|
|
|
|
*/
|
|
|
|
struct rpc_authops {
|
|
|
|
struct module *owner;
|
|
|
|
rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */
|
|
|
|
char * au_name;
|
2013-08-27 06:23:04 +07:00
|
|
|
struct rpc_auth * (*create)(struct rpc_auth_create_args *, struct rpc_clnt *);
|
2005-04-17 05:20:36 +07:00
|
|
|
void (*destroy)(struct rpc_auth *);
|
|
|
|
|
2016-09-29 22:44:37 +07:00
|
|
|
int (*hash_cred)(struct auth_cred *, unsigned int);
|
2005-04-17 05:20:36 +07:00
|
|
|
struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
|
2016-04-22 07:51:54 +07:00
|
|
|
struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int, gfp_t);
|
2012-07-12 03:31:08 +07:00
|
|
|
int (*list_pseudoflavors)(rpc_authflavor_t *, int);
|
2013-03-17 02:54:43 +07:00
|
|
|
rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *);
|
2013-03-17 02:55:10 +07:00
|
|
|
int (*flavor2info)(rpc_authflavor_t,
|
|
|
|
struct rpcsec_gss_info *);
|
2013-08-14 22:59:15 +07:00
|
|
|
int (*key_timeout)(struct rpc_auth *,
|
|
|
|
struct rpc_cred *);
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
struct rpc_credops {
|
|
|
|
const char * cr_name; /* Name of the auth flavour */
|
2006-02-02 00:19:27 +07:00
|
|
|
int (*cr_init)(struct rpc_auth *, struct rpc_cred *);
|
2005-04-17 05:20:36 +07:00
|
|
|
void (*crdestroy)(struct rpc_cred *);
|
|
|
|
|
|
|
|
int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
|
2010-08-01 01:29:08 +07:00
|
|
|
struct rpc_cred * (*crbind)(struct rpc_task *, struct rpc_cred *, int);
|
2006-09-27 12:29:38 +07:00
|
|
|
__be32 * (*crmarshal)(struct rpc_task *, __be32 *);
|
2005-04-17 05:20:36 +07:00
|
|
|
int (*crrefresh)(struct rpc_task *);
|
2006-09-27 12:29:38 +07:00
|
|
|
__be32 * (*crvalidate)(struct rpc_task *, __be32 *);
|
2010-12-14 21:59:18 +07:00
|
|
|
int (*crwrap_req)(struct rpc_task *, kxdreproc_t,
|
2006-09-27 12:29:38 +07:00
|
|
|
void *, __be32 *, void *);
|
2010-12-14 21:59:29 +07:00
|
|
|
int (*crunwrap_resp)(struct rpc_task *, kxdrdproc_t,
|
2006-09-27 12:29:38 +07:00
|
|
|
void *, __be32 *, void *);
|
2013-08-14 22:59:15 +07:00
|
|
|
int (*crkey_timeout)(struct rpc_cred *);
|
|
|
|
bool (*crkey_to_expire)(struct rpc_cred *);
|
2014-06-22 07:52:16 +07:00
|
|
|
char * (*crstringify_acceptor)(struct rpc_cred *);
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
2007-06-24 07:17:58 +07:00
|
|
|
extern const struct rpc_authops authunix_ops;
|
|
|
|
extern const struct rpc_authops authnull_ops;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2010-08-01 01:29:07 +07:00
|
|
|
int __init rpc_init_authunix(void);
|
|
|
|
int __init rpc_init_generic_auth(void);
|
|
|
|
int __init rpcauth_init_module(void);
|
2010-09-29 11:16:57 +07:00
|
|
|
void rpcauth_remove_module(void);
|
|
|
|
void rpc_destroy_generic_auth(void);
|
2010-08-01 01:29:07 +07:00
|
|
|
void rpc_destroy_authunix(void);
|
2007-06-25 02:57:57 +07:00
|
|
|
|
2008-03-12 23:24:49 +07:00
|
|
|
struct rpc_cred * rpc_lookup_cred(void);
|
2014-07-14 08:28:20 +07:00
|
|
|
struct rpc_cred * rpc_lookup_cred_nonblock(void);
|
2016-04-22 07:51:55 +07:00
|
|
|
struct rpc_cred * rpc_lookup_generic_cred(struct auth_cred *, int, gfp_t);
|
2012-01-04 01:22:46 +07:00
|
|
|
struct rpc_cred * rpc_lookup_machine_cred(const char *service_name);
|
2007-06-24 07:17:58 +07:00
|
|
|
int rpcauth_register(const struct rpc_authops *);
|
|
|
|
int rpcauth_unregister(const struct rpc_authops *);
|
2013-08-27 06:23:04 +07:00
|
|
|
struct rpc_auth * rpcauth_create(struct rpc_auth_create_args *,
|
|
|
|
struct rpc_clnt *);
|
2007-06-23 21:46:47 +07:00
|
|
|
void rpcauth_release(struct rpc_auth *);
|
2013-03-17 02:54:43 +07:00
|
|
|
rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t,
|
|
|
|
struct rpcsec_gss_info *);
|
2013-03-17 02:55:10 +07:00
|
|
|
int rpcauth_get_gssinfo(rpc_authflavor_t,
|
|
|
|
struct rpcsec_gss_info *);
|
2012-07-12 03:31:08 +07:00
|
|
|
int rpcauth_list_flavors(rpc_authflavor_t *, int);
|
2016-04-22 07:51:54 +07:00
|
|
|
struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int, gfp_t);
|
2007-06-24 06:55:31 +07:00
|
|
|
void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
|
2005-04-17 05:20:36 +07:00
|
|
|
struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int);
|
2010-08-01 01:29:08 +07:00
|
|
|
struct rpc_cred * rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int);
|
2005-04-17 05:20:36 +07:00
|
|
|
void put_rpccred(struct rpc_cred *);
|
2006-09-27 12:29:38 +07:00
|
|
|
__be32 * rpcauth_marshcred(struct rpc_task *, __be32 *);
|
|
|
|
__be32 * rpcauth_checkverf(struct rpc_task *, __be32 *);
|
2010-12-14 21:59:18 +07:00
|
|
|
int rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp, __be32 *data, void *obj);
|
2010-12-14 21:59:29 +07:00
|
|
|
int rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *data, void *obj);
|
2005-04-17 05:20:36 +07:00
|
|
|
int rpcauth_refreshcred(struct rpc_task *);
|
|
|
|
void rpcauth_invalcred(struct rpc_task *);
|
|
|
|
int rpcauth_uptodatecred(struct rpc_task *);
|
2007-06-26 04:11:20 +07:00
|
|
|
int rpcauth_init_credcache(struct rpc_auth *);
|
2007-06-10 02:41:42 +07:00
|
|
|
void rpcauth_destroy_credcache(struct rpc_auth *);
|
|
|
|
void rpcauth_clear_credcache(struct rpc_cred_cache *);
|
2013-08-14 22:59:15 +07:00
|
|
|
int rpcauth_key_timeout_notify(struct rpc_auth *,
|
|
|
|
struct rpc_cred *);
|
sunrpc: move NO_CRKEY_TIMEOUT to the auth->au_flags
A generic_cred can be used to look up a unx_cred or a gss_cred, so it's
not really safe to use the the generic_cred->acred->ac_flags to store
the NO_CRKEY_TIMEOUT flag. A lookup for a unx_cred triggered while the
KEY_EXPIRE_SOON flag is already set will cause both NO_CRKEY_TIMEOUT and
KEY_EXPIRE_SOON to be set in the ac_flags, leaving the user associated
with the auth_cred to be in a state where they're perpetually doing 4K
NFS_FILE_SYNC writes.
This can be reproduced as follows:
1. Mount two NFS filesystems, one with sec=krb5 and one with sec=sys.
They do not need to be the same export, nor do they even need to be from
the same NFS server. Also, v3 is fine.
$ sudo mount -o v3,sec=krb5 server1:/export /mnt/krb5
$ sudo mount -o v3,sec=sys server2:/export /mnt/sys
2. As the normal user, before accessing the kerberized mount, kinit with
a short lifetime (but not so short that renewing the ticket would leave
you within the 4-minute window again by the time the original ticket
expires), e.g.
$ kinit -l 10m -r 60m
3. Do some I/O to the kerberized mount and verify that the writes are
wsize, UNSTABLE:
$ dd if=/dev/zero of=/mnt/krb5/file bs=1M count=1
4. Wait until you're within 4 minutes of key expiry, then do some more
I/O to the kerberized mount to ensure that RPC_CRED_KEY_EXPIRE_SOON gets
set. Verify that the writes are 4K, FILE_SYNC:
$ dd if=/dev/zero of=/mnt/krb5/file bs=1M count=1
5. Now do some I/O to the sec=sys mount. This will cause
RPC_CRED_NO_CRKEY_TIMEOUT to be set:
$ dd if=/dev/zero of=/mnt/sys/file bs=1M count=1
6. Writes for that user will now be permanently 4K, FILE_SYNC for that
user, regardless of which mount is being written to, until you reboot
the client. Renewing the kerberos ticket (assuming it hasn't already
expired) will have no effect. Grabbing a new kerberos ticket at this
point will have no effect either.
Move the flag to the auth->au_flags field (which is currently unused)
and rename it slightly to reflect that it's no longer associated with
the auth_cred->ac_flags. Add the rpc_auth to the arg list of
rpcauth_cred_key_to_expire and check the au_flags there too. Finally,
add the inode to the arg list of nfs_ctx_key_to_expire so we can
determine the rpc_auth to pass to rpcauth_cred_key_to_expire.
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
2016-06-08 02:14:48 +07:00
|
|
|
bool rpcauth_cred_key_to_expire(struct rpc_auth *, struct rpc_cred *);
|
2014-06-22 07:52:16 +07:00
|
|
|
char * rpcauth_stringify_acceptor(struct rpc_cred *);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
static inline
|
|
|
|
struct rpc_cred * get_rpccred(struct rpc_cred *cred)
|
|
|
|
{
|
2016-05-17 04:42:42 +07:00
|
|
|
if (cred != NULL)
|
|
|
|
atomic_inc(&cred->cr_count);
|
2005-04-17 05:20:36 +07:00
|
|
|
return cred;
|
|
|
|
}
|
|
|
|
|
2016-04-22 07:51:56 +07:00
|
|
|
/**
|
|
|
|
* get_rpccred_rcu - get a reference to a cred using rcu-protected pointer
|
|
|
|
* @cred: cred of which to take a reference
|
|
|
|
*
|
|
|
|
* In some cases, we may have a pointer to a credential to which we
|
|
|
|
* want to take a reference, but don't already have one. Because these
|
|
|
|
* objects are freed using RCU, we can access the cr_count while its
|
|
|
|
* on its way to destruction and only take a reference if it's not already
|
|
|
|
* zero.
|
|
|
|
*/
|
|
|
|
static inline struct rpc_cred *
|
|
|
|
get_rpccred_rcu(struct rpc_cred *cred)
|
|
|
|
{
|
|
|
|
if (atomic_inc_not_zero(&cred->cr_count))
|
|
|
|
return cred;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif /* __KERNEL__ */
|
|
|
|
#endif /* _LINUX_SUNRPC_AUTH_H */
|