linux/net/sunrpc/auth_gss/svcauth_gss.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Neil Brown <[email protected]>
 * J. Bruce Fields <[email protected]>
 * Andy Adamson <[email protected]>
 * Dug Song <[email protected]>
 *
 * RPCSEC_GSS server authentication.
 * This implements RPCSEC_GSS as defined in rfc2203 (rpcsec_gss) and rfc2078
 * (gssapi)
 *
 * The RPCSEC_GSS involves three stages:
 *  1/ context creation
 *  2/ data exchange
 *  3/ context destruction
 *
 * Context creation is handled largely by upcalls to user-space.
 *  In particular, GSS_Accept_sec_context is handled by an upcall
 * Data exchange is handled entirely within the kernel
 *  In particular, GSS_GetMIC, GSS_VerifyMIC, GSS_Seal, GSS_Unseal are in-kernel.
 * Context destruction is handled in-kernel
 *  GSS_Delete_sec_context is in-kernel
 *
 * Context creation is initiated by a RPCSEC_GSS_INIT request arriving.
 * The context handle and gss_token are used as a key into the rpcsec_init cache.
 * The content of this cache includes some of the outputs of GSS_Accept_sec_context,
 * being major_status, minor_status, context_handle, reply_token.
 * These are sent back to the client.
 * Sequence window management is handled by the kernel.  The window size if currently
 * a compile time constant.
 *
 * When user-space is happy that a context is established, it places an entry
 * in the rpcsec_context cache. The key for this cache is the context_handle.
 * The content includes:
 *   uid/gidlist - for determining access rights
 *   mechanism type
 *   mechanism specific information, such as a key
 *
 */

#include <linux/slab.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/user_namespace.h>

#include <linux/sunrpc/auth_gss.h>
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/svcauth.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/cache.h>
#include <linux/sunrpc/gss_krb5.h>

#include <trace/events/rpcgss.h>

#include "gss_rpc_upcall.h"

/*
 * Unfortunately there isn't a maximum checksum size exported via the
 * GSS API. Manufacture one based on GSS mechanisms supported by this
 * implementation.
 */
#define GSS_MAX_CKSUMSIZE

/*
 * This value may be increased in the future to accommodate other
 * usage of the scratch buffer.
 */
#define GSS_SCRATCH_SIZE

struct gss_svc_data {};

/* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests
 * into replies.
 *
 * Key is context handle (\x if empty) and gss_token.
 * Content is major_status minor_status (integers) context_handle, reply_token.
 *
 */

static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b)
{}

#define RSI_HASHBITS
#define RSI_HASHMAX

struct rsi {};

static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old);
static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item);

static void rsi_free(struct rsi *rsii)
{}

static void rsi_free_rcu(struct rcu_head *head)
{}

static void rsi_put(struct kref *ref)
{}

static inline int rsi_hash(struct rsi *item)
{}

static int rsi_match(struct cache_head *a, struct cache_head *b)
{}

static int dup_to_netobj(struct xdr_netobj *dst, char *src, int len)
{}

static inline int dup_netobj(struct xdr_netobj *dst, struct xdr_netobj *src)
{}

static void rsi_init(struct cache_head *cnew, struct cache_head *citem)
{}

static void update_rsi(struct cache_head *cnew, struct cache_head *citem)
{}

static struct cache_head *rsi_alloc(void)
{}

static int rsi_upcall(struct cache_detail *cd, struct cache_head *h)
{}

static void rsi_request(struct cache_detail *cd,
		       struct cache_head *h,
		       char **bpp, int *blen)
{}

static int rsi_parse(struct cache_detail *cd,
		    char *mesg, int mlen)
{}

static const struct cache_detail rsi_cache_template =;

static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item)
{}

static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old)
{}


/*
 * The rpcsec_context cache is used to store a context that is
 * used in data exchange.
 * The key is a context handle. The content is:
 *  uid, gidlist, mechanism, service-set, mech-specific-data
 */

#define RSC_HASHBITS
#define RSC_HASHMAX

#define GSS_SEQ_WIN

struct gss_svc_seq_data {};

struct rsc {};

static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old);
static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item);

static void rsc_free(struct rsc *rsci)
{}

static void rsc_free_rcu(struct rcu_head *head)
{}

static void rsc_put(struct kref *ref)
{}

static inline int
rsc_hash(struct rsc *rsci)
{}

static int
rsc_match(struct cache_head *a, struct cache_head *b)
{}

static void
rsc_init(struct cache_head *cnew, struct cache_head *ctmp)
{}

static void
update_rsc(struct cache_head *cnew, struct cache_head *ctmp)
{}

static struct cache_head *
rsc_alloc(void)
{}

static int rsc_upcall(struct cache_detail *cd, struct cache_head *h)
{}

static int rsc_parse(struct cache_detail *cd,
		     char *mesg, int mlen)
{}

static const struct cache_detail rsc_cache_template =;

static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item)
{}

static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old)
{}


static struct rsc *
gss_svc_searchbyctx(struct cache_detail *cd, struct xdr_netobj *handle)
{}

/**
 * gss_check_seq_num - GSS sequence number window check
 * @rqstp: RPC Call to use when reporting errors
 * @rsci: cached GSS context state (updated on return)
 * @seq_num: sequence number to check
 *
 * Implements sequence number algorithm as specified in
 * RFC 2203, Section 5.3.3.1. "Context Management".
 *
 * Return values:
 *   %true: @rqstp's GSS sequence number is inside the window
 *   %false: @rqstp's GSS sequence number is outside the window
 */
static bool gss_check_seq_num(const struct svc_rqst *rqstp, struct rsc *rsci,
			      u32 seq_num)
{}

/*
 * Decode and verify a Call's verifier field. For RPC_AUTH_GSS Calls,
 * the body of this field contains a variable length checksum.
 *
 * GSS-specific auth_stat values are mandated by RFC 2203 Section
 * 5.3.3.3.
 */
static int
svcauth_gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
			  __be32 *rpcstart, struct rpc_gss_wire_cred *gc)
{}

/*
 * Construct and encode a Reply's verifier field. The verifier's body
 * field contains a variable-length checksum of the GSS sequence
 * number.
 */
static bool
svcauth_gss_encode_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
{}

struct gss_domain {};

static struct auth_domain *
find_gss_auth_domain(struct gss_ctx *ctx, u32 svc)
{}

static struct auth_ops svcauthops_gss;

u32 svcauth_gss_flavor(struct auth_domain *dom)
{}

EXPORT_SYMBOL_GPL();

struct auth_domain *
svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
{}
EXPORT_SYMBOL_GPL();

/*
 * 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
svcauth_gss_unwrap_integ(struct svc_rqst *rqstp, u32 seq, struct gss_ctx *ctx)
{}

/*
 * RFC 2203, Section 5.3.2.3
 *
 *	struct rpc_gss_priv_data {
 *		opaque databody_priv<>
 *	};
 *
 *	struct rpc_gss_data_t {
 *		unsigned int seq_num;
 *		proc_req_arg_t arg;
 *	};
 */
static noinline_for_stack int
svcauth_gss_unwrap_priv(struct svc_rqst *rqstp, u32 seq, struct gss_ctx *ctx)
{}

static enum svc_auth_status
svcauth_gss_set_client(struct svc_rqst *rqstp)
{}

static bool
svcauth_gss_proc_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp,
			   struct xdr_netobj *out_handle, int *major_status,
			   u32 seq_num)
{}

static void gss_free_in_token_pages(struct gssp_in_token *in_token)
{}

static int gss_read_proxy_verf(struct svc_rqst *rqstp,
			       struct rpc_gss_wire_cred *gc,
			       struct xdr_netobj *in_handle,
			       struct gssp_in_token *in_token)
{}

/*
 * RFC 2203, Section 5.2.3.1.
 *
 *	struct rpc_gss_init_res {
 *		opaque handle<>;
 *		unsigned int gss_major;
 *		unsigned int gss_minor;
 *		unsigned int seq_window;
 *		opaque gss_token<>;
 *	};
 */
static bool
svcxdr_encode_gss_init_res(struct xdr_stream *xdr,
			   struct xdr_netobj *handle,
			   struct xdr_netobj *gss_token,
			   unsigned int major_status,
			   unsigned int minor_status, u32 seq_num)
{}

/*
 * Having read the cred already and found we're in the context
 * initiation case, read the verifier and initiate (or check the results
 * of) upcalls to userspace for help with context initiation.  If
 * the upcall results are available, write the verifier and result.
 * Otherwise, drop the request pending an answer to the upcall.
 */
static int
svcauth_gss_legacy_init(struct svc_rqst *rqstp,
			struct rpc_gss_wire_cred *gc)
{}

static int gss_proxy_save_rsc(struct cache_detail *cd,
				struct gssp_upcall_data *ud,
				uint64_t *handle)
{}

static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
				  struct rpc_gss_wire_cred *gc)
{}

/*
 * Try to set the sn->use_gss_proxy variable to a new value. We only allow
 * it to be changed if it's currently undefined (-1). If it's any other value
 * then return -EBUSY unless the type wouldn't have changed anyway.
 */
static int set_gss_proxy(struct net *net, int type)
{}

static bool use_gss_proxy(struct net *net)
{}

static noinline_for_stack int
svcauth_gss_proc_init(struct svc_rqst *rqstp, struct rpc_gss_wire_cred *gc)
{}

#ifdef CONFIG_PROC_FS

static ssize_t write_gssp(struct file *file, const char __user *buf,
			 size_t count, loff_t *ppos)
{}

static ssize_t read_gssp(struct file *file, char __user *buf,
			 size_t count, loff_t *ppos)
{}

static const struct proc_ops use_gss_proxy_proc_ops =;

static int create_use_gss_proxy_proc_entry(struct net *net)
{}

static void destroy_use_gss_proxy_proc_entry(struct net *net)
{}

static ssize_t read_gss_krb5_enctypes(struct file *file, char __user *buf,
				      size_t count, loff_t *ppos)
{}

static const struct proc_ops gss_krb5_enctypes_proc_ops =;

static int create_krb5_enctypes_proc_entry(struct net *net)
{}

static void destroy_krb5_enctypes_proc_entry(struct net *net)
{}

#else /* CONFIG_PROC_FS */

static int create_use_gss_proxy_proc_entry(struct net *net)
{
	return 0;
}

static void destroy_use_gss_proxy_proc_entry(struct net *net) {}

static int create_krb5_enctypes_proc_entry(struct net *net)
{
	return 0;
}

static void destroy_krb5_enctypes_proc_entry(struct net *net) {}

#endif /* CONFIG_PROC_FS */

/*
 * The Call's credential body should contain a struct rpc_gss_cred_t.
 *
 * RFC 2203 Section 5
 *
 *	struct rpc_gss_cred_t {
 *		union switch (unsigned int version) {
 *		case RPCSEC_GSS_VERS_1:
 *			struct {
 *				rpc_gss_proc_t gss_proc;
 *				unsigned int seq_num;
 *				rpc_gss_service_t service;
 *				opaque handle<>;
 *			} rpc_gss_cred_vers_1_t;
 *		}
 *	};
 */
static bool
svcauth_gss_decode_credbody(struct xdr_stream *xdr,
			    struct rpc_gss_wire_cred *gc,
			    __be32 **rpcstart)
{}

/**
 * svcauth_gss_accept - Decode and validate incoming RPC_AUTH_GSS credential
 * @rqstp: RPC transaction
 *
 * Return values:
 *   %SVC_OK: Success
 *   %SVC_COMPLETE: GSS context lifetime event
 *   %SVC_DENIED: Credential or verifier is not valid
 *   %SVC_GARBAGE: Failed to decode credential or verifier
 *   %SVC_CLOSE: Temporary failure
 *
 * The rqstp->rq_auth_stat field is also set (see RFCs 2203 and 5531).
 */
static enum svc_auth_status
svcauth_gss_accept(struct svc_rqst *rqstp)
{}

static u32
svcauth_gss_prepare_to_wrap(struct svc_rqst *rqstp, struct gss_svc_data *gsd)
{}

/*
 * 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;
 *	};
 *
 * The RPC Reply message has already been XDR-encoded. rq_res_stream
 * is now positioned so that the checksum can be written just past
 * the RPC Reply message.
 */
static int svcauth_gss_wrap_integ(struct svc_rqst *rqstp)
{}

/*
 * RFC 2203, Section 5.3.2.3
 *
 *	struct rpc_gss_priv_data {
 *		opaque databody_priv<>
 *	};
 *
 *	struct rpc_gss_data_t {
 *		unsigned int seq_num;
 *		proc_req_arg_t arg;
 *	};
 *
 * gss_wrap() expands the size of the RPC message payload in the
 * response buffer. The main purpose of svcauth_gss_wrap_priv()
 * is to ensure there is adequate space in the response buffer to
 * avoid overflow during the wrap.
 */
static int svcauth_gss_wrap_priv(struct svc_rqst *rqstp)
{}

/**
 * svcauth_gss_release - Wrap payload and release resources
 * @rqstp: RPC transaction context
 *
 * Return values:
 *    %0: the Reply is ready to be sent
 *    %-ENOMEM: failed to allocate memory
 *    %-EINVAL: encoding error
 */
static int
svcauth_gss_release(struct svc_rqst *rqstp)
{}

static void
svcauth_gss_domain_release_rcu(struct rcu_head *head)
{}

static void
svcauth_gss_domain_release(struct auth_domain *dom)
{}

static rpc_authflavor_t svcauth_gss_pseudoflavor(struct svc_rqst *rqstp)
{}

static struct auth_ops svcauthops_gss =;

static int rsi_cache_create_net(struct net *net)
{}

static void rsi_cache_destroy_net(struct net *net)
{}

static int rsc_cache_create_net(struct net *net)
{}

static void rsc_cache_destroy_net(struct net *net)
{}

int
gss_svc_init_net(struct net *net)
{}

void
gss_svc_shutdown_net(struct net *net)
{}

int
gss_svc_init(void)
{}

void
gss_svc_shutdown(void)
{}