net/sunrpc/auth_gss/gss_krb5_wrap.c

Source file repositories/reference/linux-study-clean/net/sunrpc/auth_gss/gss_krb5_wrap.c

File Facts

System
Linux kernel
Corpus path
net/sunrpc/auth_gss/gss_krb5_wrap.c
Extension
.c
Size
7062 bytes
Lines
237
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

#include <linux/types.h>
#include <linux/jiffies.h>
#include <linux/sunrpc/gss_krb5.h>
#include <linux/pagemap.h>

#include "gss_krb5_internal.h"

#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY	RPCDBG_AUTH
#endif

/*
 * We can shift data by up to LOCAL_BUF_LEN bytes in a pass.  If we need
 * to do more than that, we shift repeatedly.  Kevin Coffman reports
 * seeing 28 bytes as the value used by Microsoft clients and servers
 * with AES, so this constant is chosen to allow handling 28 in one pass
 * without using too much stack space.
 *
 * If that proves to a problem perhaps we could use a more clever
 * algorithm.
 */
#define LOCAL_BUF_LEN 32u

static void rotate_buf_a_little(struct xdr_buf *buf, unsigned int shift)
{
	char head[LOCAL_BUF_LEN];
	char tmp[LOCAL_BUF_LEN];
	unsigned int this_len, i;

	BUG_ON(shift > LOCAL_BUF_LEN);

	read_bytes_from_xdr_buf(buf, 0, head, shift);
	for (i = 0; i + shift < buf->len; i += LOCAL_BUF_LEN) {
		this_len = min(LOCAL_BUF_LEN, buf->len - (i + shift));
		read_bytes_from_xdr_buf(buf, i+shift, tmp, this_len);
		write_bytes_to_xdr_buf(buf, i, tmp, this_len);
	}
	write_bytes_to_xdr_buf(buf, buf->len - shift, head, shift);
}

static void _rotate_left(struct xdr_buf *buf, unsigned int shift)
{
	int shifted = 0;
	int this_shift;

	shift %= buf->len;
	while (shifted < shift) {
		this_shift = min(shift - shifted, LOCAL_BUF_LEN);
		rotate_buf_a_little(buf, this_shift);
		shifted += this_shift;
	}
}

static void rotate_left(u32 base, struct xdr_buf *buf, unsigned int shift)
{
	struct xdr_buf subbuf;

	xdr_buf_subsegment(buf, &subbuf, base, buf->len - base);
	_rotate_left(&subbuf, shift);
}

u32
gss_krb5_wrap_v2(struct krb5_ctx *kctx, int offset,
		 struct xdr_buf *buf, struct page **pages)
{
	u8		*ptr;
	time64_t	now;
	u8		flags = 0x00;
	__be16		*be16ptr;
	__be64		*be64ptr;
	u32		err;

	dprintk("RPC:       %s\n", __func__);

	/* make room for gss token header */
	if (xdr_extend_head(buf, offset, GSS_KRB5_TOK_HDR_LEN))
		return GSS_S_FAILURE;

	/* construct gss token header */
	ptr = buf->head[0].iov_base + offset;
	*ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff);
	*ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff);

	if (!kctx->initiate)
		flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR;
	if (kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
		flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY;
	/* We always do confidentiality in wrap tokens */
	flags |= KG2_TOKEN_FLAG_SEALED;

Annotation

Implementation Notes