linux/net/sunrpc/auth_gss/auth_gss.c

// SPDX-License-Identifier: BSD-3-Clause
/*
 * linux/net/sunrpc/auth_gss/auth_gss.c
 *
 * RPCSEC_GSS client authentication.
 *
 *  Copyright (c) 2000 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Dug Song       <[email protected]>
 *  Andy Adamson   <[email protected]>
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/pagemap.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/auth.h>
#include <linux/sunrpc/auth_gss.h>
#include <linux/sunrpc/gss_krb5.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/gss_err.h>
#include <linux/workqueue.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/sunrpc/gss_api.h>
#include <linux/uaccess.h>
#include <linux/hashtable.h>

#include "auth_gss_internal.h"
#include "../netns.h"

#include <trace/events/rpcgss.h>

static const struct rpc_authops authgss_ops;

static const struct rpc_credops gss_credops;
static const struct rpc_credops gss_nullops;

#define GSS_RETRY_EXPIRED
static unsigned int gss_expired_cred_retry_delay =;

#define GSS_KEY_EXPIRE_TIMEO
static unsigned int gss_key_expire_timeo =;

#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
#define RPCDBG_FACILITY
#endif

/*
 * This compile-time check verifies that we will not exceed the
 * slack space allotted by the client and server auth_gss code
 * before they call gss_wrap().
 */
#define GSS_KRB5_MAX_SLACK_NEEDED

#define GSS_CRED_SLACK
/* length of a krb5 verifier (48), plus data added before arguments when
 * using integrity (two 4-byte integers): */
#define GSS_VERF_SLACK

static DEFINE_HASHTABLE(gss_auth_hash_table, 4);
static DEFINE_SPINLOCK(gss_auth_hash_lock);

struct gss_pipe {};

struct gss_auth {};

/* pipe_version >= 0 if and only if someone has a pipe open. */
static DEFINE_SPINLOCK(pipe_version_lock);
static struct rpc_wait_queue pipe_version_rpc_waitqueue;
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
static void gss_put_auth(struct gss_auth *gss_auth);

static void gss_free_ctx(struct gss_cl_ctx *);
static const struct rpc_pipe_ops gss_upcall_ops_v0;
static const struct rpc_pipe_ops gss_upcall_ops_v1;

static inline struct gss_cl_ctx *
gss_get_ctx(struct gss_cl_ctx *ctx)
{}

static inline void
gss_put_ctx(struct gss_cl_ctx *ctx)
{}

/* gss_cred_set_ctx:
 * called by gss_upcall_callback and gss_create_upcall in order
 * to set the gss context. The actual exchange of an old context
 * and a new one is protected by the pipe->lock.
 */
static void
gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
{}

static struct gss_cl_ctx *
gss_cred_get_ctx(struct rpc_cred *cred)
{}

static struct gss_cl_ctx *
gss_alloc_context(void)
{}

#define GSSD_MIN_TIMEOUT
static const void *
gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct gss_api_mech *gm)
{}

/* XXX: Need some documentation about why UPCALL_BUF_LEN is so small.
 *	Is user space expecting no more than UPCALL_BUF_LEN bytes?
 *	Note that there are now _two_ NI_MAXHOST sized data items
 *	being passed in this string.
 */
#define UPCALL_BUF_LEN

struct gss_upcall_msg {};

static int get_pipe_version(struct net *net)
{}

static void put_pipe_version(struct net *net)
{}

static void
gss_release_msg(struct gss_upcall_msg *gss_msg)
{}

static struct gss_upcall_msg *
__gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid, const struct gss_auth *auth)
{}

/* Try to add an upcall to the pipefs queue.
 * If an upcall owned by our uid already exists, then we return a reference
 * to that upcall instead of adding the new upcall.
 */
static inline struct gss_upcall_msg *
gss_add_msg(struct gss_upcall_msg *gss_msg)
{}

static void
__gss_unhash_msg(struct gss_upcall_msg *gss_msg)
{}

static void
gss_unhash_msg(struct gss_upcall_msg *gss_msg)
{}

static void
gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss_msg)
{}

static void
gss_upcall_callback(struct rpc_task *task)
{}

static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg,
			      const struct cred *cred)
{}

static ssize_t
gss_v0_upcall(struct file *file, struct rpc_pipe_msg *msg,
		char __user *buf, size_t buflen)
{}

static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
				const char *service_name,
				const char *target_name,
				const struct cred *cred)
{}

static ssize_t
gss_v1_upcall(struct file *file, struct rpc_pipe_msg *msg,
		char __user *buf, size_t buflen)
{}

static struct gss_upcall_msg *
gss_alloc_msg(struct gss_auth *gss_auth,
		kuid_t uid, const char *service_name)
{}

static struct gss_upcall_msg *
gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred)
{}

static void warn_gssd(void)
{}

static inline int
gss_refresh_upcall(struct rpc_task *task)
{}

static inline int
gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
{}

static struct gss_upcall_msg *
gss_find_downcall(struct rpc_pipe *pipe, kuid_t uid)
{}

#define MSG_BUF_MAXSIZE

static ssize_t
gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
{}

static int gss_pipe_open(struct inode *inode, int new_version)
{}

static int gss_pipe_open_v0(struct inode *inode)
{}

static int gss_pipe_open_v1(struct inode *inode)
{}

static void
gss_pipe_release(struct inode *inode)
{}

static void
gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
{}

static void gss_pipe_dentry_destroy(struct dentry *dir,
		struct rpc_pipe_dir_object *pdo)
{}

static int gss_pipe_dentry_create(struct dentry *dir,
		struct rpc_pipe_dir_object *pdo)
{}

static const struct rpc_pipe_dir_object_ops gss_pipe_dir_object_ops =;

static struct gss_pipe *gss_pipe_alloc(struct rpc_clnt *clnt,
		const char *name,
		const struct rpc_pipe_ops *upcall_ops)
{}

struct gss_alloc_pdo {};

static int gss_pipe_match_pdo(struct rpc_pipe_dir_object *pdo, void *data)
{}

static struct rpc_pipe_dir_object *gss_pipe_alloc_pdo(void *data)
{}

static struct gss_pipe *gss_pipe_get(struct rpc_clnt *clnt,
		const char *name,
		const struct rpc_pipe_ops *upcall_ops)
{}

static void __gss_pipe_free(struct gss_pipe *p)
{}

static void __gss_pipe_release(struct kref *kref)
{}

static void gss_pipe_free(struct gss_pipe *p)
{}

/*
 * NOTE: we have the opportunity to use different
 * parameters based on the input flavor (which must be a pseudoflavor)
 */
static struct gss_auth *
gss_create_new(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
{}

static void
gss_free(struct gss_auth *gss_auth)
{}

static void
gss_free_callback(struct kref *kref)
{}

static void
gss_put_auth(struct gss_auth *gss_auth)
{}

static void
gss_destroy(struct rpc_auth *auth)
{}

/*
 * Auths may be shared between rpc clients that were cloned from a
 * common client with the same xprt, if they also share the flavor and
 * target_name.
 *
 * The auth is looked up from the oldest parent sharing the same
 * cl_xprt, and the auth itself references only that common parent
 * (which is guaranteed to last as long as any of its descendants).
 */
static struct gss_auth *
gss_auth_find_or_add_hashed(const struct rpc_auth_create_args *args,
		struct rpc_clnt *clnt,
		struct gss_auth *new)
{}

static struct gss_auth *
gss_create_hashed(const struct rpc_auth_create_args *args,
		  struct rpc_clnt *clnt)
{}

static struct rpc_auth *
gss_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
{}

static struct gss_cred *
gss_dup_cred(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
{}

/*
 * gss_send_destroy_context will cause the RPCSEC_GSS to send a NULL RPC call
 * to the server with the GSS control procedure field set to
 * RPC_GSS_PROC_DESTROY. This should normally cause the server to release
 * all RPCSEC_GSS state associated with that context.
 */
static void
gss_send_destroy_context(struct rpc_cred *cred)
{}

/* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure
 * to create a new cred or context, so they check that things have been
 * allocated before freeing them. */
static void
gss_do_free_ctx(struct gss_cl_ctx *ctx)
{}

static void
gss_free_ctx_callback(struct rcu_head *head)
{}

static void
gss_free_ctx(struct gss_cl_ctx *ctx)
{}

static void
gss_free_cred(struct gss_cred *gss_cred)
{}

static void
gss_free_cred_callback(struct rcu_head *head)
{}

static void
gss_destroy_nullcred(struct rpc_cred *cred)
{}

static void
gss_destroy_cred(struct rpc_cred *cred)
{}

static int
gss_hash_cred(struct auth_cred *acred, unsigned int hashbits)
{}

/*
 * Lookup RPCSEC_GSS cred for the current process
 */
static struct rpc_cred *gss_lookup_cred(struct rpc_auth *auth,
					struct auth_cred *acred, int flags)
{}

static struct rpc_cred *
gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t gfp)
{}

static int
gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
{}

static char *
gss_stringify_acceptor(struct rpc_cred *cred)
{}

/*
 * Returns -EACCES if GSS context is NULL or will expire within the
 * timeout (miliseconds)
 */
static int
gss_key_timeout(struct rpc_cred *rc)
{}

static int
gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
{}

/*
 * Marshal credentials.
 *
 * The expensive part is computing the verifier. We can't cache a
 * pre-computed version of the verifier because the seqno, which
 * is different every time, is included in the MIC.
 */
static int gss_marshal(struct rpc_task *task, struct xdr_stream *xdr)
{}

static int gss_renew_cred(struct rpc_task *task)
{}

static int gss_cred_is_negative_entry(struct rpc_cred *cred)
{}

/*
* Refresh credentials. XXX - finish
*/
static int
gss_refresh(struct rpc_task *task)
{}

/* Dummy refresh routine: used only when destroying the context */
static int
gss_refresh_null(struct rpc_task *task)
{}

static int
gss_validate(struct rpc_task *task, struct xdr_stream *xdr)
{}

static noinline_for_stack int
gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
		   struct rpc_task *task, struct xdr_stream *xdr)
{}

static void
priv_release_snd_buf(struct rpc_rqst *rqstp)
{}

static int
alloc_enc_pages(struct rpc_rqst *rqstp)
{}

static noinline_for_stack int
gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
		  struct rpc_task *task, struct xdr_stream *xdr)
{}

static int gss_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
{}

/**
 * gss_update_rslack - Possibly update RPC receive buffer size estimates
 * @task: rpc_task for incoming RPC Reply being unwrapped
 * @cred: controlling rpc_cred for @task
 * @before: XDR words needed before each RPC Reply message
 * @after: XDR words needed following each RPC Reply message
 *
 */
static void gss_update_rslack(struct rpc_task *task, struct rpc_cred *cred,
			      unsigned int before, unsigned int after)
{}

static int
gss_unwrap_resp_auth(struct rpc_task *task, struct rpc_cred *cred)
{}

/*
 * RFC 2203, Section 5.3.2.2
 *
 *	struct rpc_gss_integ_data {
 *		opaque databody_integ<>;
 *		opaque checksum<>;
 *	};
 *
 *	struct rpc_gss_data_t {
 *		unsigned int seq_num;
 *		proc_req_arg_t arg;
 *	};
 */
static noinline_for_stack int
gss_unwrap_resp_integ(struct rpc_task *task, struct rpc_cred *cred,
		      struct gss_cl_ctx *ctx, struct rpc_rqst *rqstp,
		      struct xdr_stream *xdr)
{}

static noinline_for_stack int
gss_unwrap_resp_priv(struct rpc_task *task, struct rpc_cred *cred,
		     struct gss_cl_ctx *ctx, struct rpc_rqst *rqstp,
		     struct xdr_stream *xdr)
{}

static bool
gss_seq_is_newer(u32 new, u32 old)
{}

static bool
gss_xmit_need_reencode(struct rpc_task *task)
{}

static int
gss_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr)
{}

static const struct rpc_authops authgss_ops =;

static const struct rpc_credops gss_credops =;

static const struct rpc_credops gss_nullops =;

static const struct rpc_pipe_ops gss_upcall_ops_v0 =;

static const struct rpc_pipe_ops gss_upcall_ops_v1 =;

static __net_init int rpcsec_gss_init_net(struct net *net)
{}

static __net_exit void rpcsec_gss_exit_net(struct net *net)
{}

static struct pernet_operations rpcsec_gss_net_ops =;

/*
 * Initialize RPCSEC_GSS module
 */
static int __init init_rpcsec_gss(void)
{}

static void __exit exit_rpcsec_gss(void)
{}

MODULE_ALIAS();
MODULE_DESCRIPTION();
MODULE_LICENSE();
module_param_named(expired_cred_retry_delay,
		   gss_expired_cred_retry_delay,
		   uint, 0644);
MODULE_PARM_DESC();

module_param_named(key_expire_timeo,
		   gss_key_expire_timeo,
		   uint, 0644);
MODULE_PARM_DESC();

module_init()
module_exit()