162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/net/sunrpc/gss_mech_switch.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 2001 The Regents of the University of Michigan.
662306a36Sopenharmony_ci *  All rights reserved.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  J. Bruce Fields   <bfields@umich.edu>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/oid_registry.h>
1562306a36Sopenharmony_ci#include <linux/sunrpc/msg_prot.h>
1662306a36Sopenharmony_ci#include <linux/sunrpc/gss_asn1.h>
1762306a36Sopenharmony_ci#include <linux/sunrpc/auth_gss.h>
1862306a36Sopenharmony_ci#include <linux/sunrpc/svcauth_gss.h>
1962306a36Sopenharmony_ci#include <linux/sunrpc/gss_err.h>
2062306a36Sopenharmony_ci#include <linux/sunrpc/sched.h>
2162306a36Sopenharmony_ci#include <linux/sunrpc/gss_api.h>
2262306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h>
2362306a36Sopenharmony_ci#include <trace/events/rpcgss.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
2662306a36Sopenharmony_ci# define RPCDBG_FACILITY        RPCDBG_AUTH
2762306a36Sopenharmony_ci#endif
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic LIST_HEAD(registered_mechs);
3062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(registered_mechs_lock);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void
3362306a36Sopenharmony_cigss_mech_free(struct gss_api_mech *gm)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	struct pf_desc *pf;
3662306a36Sopenharmony_ci	int i;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
3962306a36Sopenharmony_ci		pf = &gm->gm_pfs[i];
4062306a36Sopenharmony_ci		if (pf->domain)
4162306a36Sopenharmony_ci			auth_domain_put(pf->domain);
4262306a36Sopenharmony_ci		kfree(pf->auth_domain_name);
4362306a36Sopenharmony_ci		pf->auth_domain_name = NULL;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic inline char *
4862306a36Sopenharmony_cimake_auth_domain_name(char *name)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	static char	*prefix = "gss/";
5162306a36Sopenharmony_ci	char		*new;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	new = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL);
5462306a36Sopenharmony_ci	if (new) {
5562306a36Sopenharmony_ci		strcpy(new, prefix);
5662306a36Sopenharmony_ci		strcat(new, name);
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci	return new;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int
6262306a36Sopenharmony_cigss_mech_svc_setup(struct gss_api_mech *gm)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct auth_domain *dom;
6562306a36Sopenharmony_ci	struct pf_desc *pf;
6662306a36Sopenharmony_ci	int i, status;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
6962306a36Sopenharmony_ci		pf = &gm->gm_pfs[i];
7062306a36Sopenharmony_ci		pf->auth_domain_name = make_auth_domain_name(pf->name);
7162306a36Sopenharmony_ci		status = -ENOMEM;
7262306a36Sopenharmony_ci		if (pf->auth_domain_name == NULL)
7362306a36Sopenharmony_ci			goto out;
7462306a36Sopenharmony_ci		dom = svcauth_gss_register_pseudoflavor(
7562306a36Sopenharmony_ci			pf->pseudoflavor, pf->auth_domain_name);
7662306a36Sopenharmony_ci		if (IS_ERR(dom)) {
7762306a36Sopenharmony_ci			status = PTR_ERR(dom);
7862306a36Sopenharmony_ci			goto out;
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci		pf->domain = dom;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ciout:
8462306a36Sopenharmony_ci	gss_mech_free(gm);
8562306a36Sopenharmony_ci	return status;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/**
8962306a36Sopenharmony_ci * gss_mech_register - register a GSS mechanism
9062306a36Sopenharmony_ci * @gm: GSS mechanism handle
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * Returns zero if successful, or a negative errno.
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_ciint gss_mech_register(struct gss_api_mech *gm)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	int status;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	status = gss_mech_svc_setup(gm);
9962306a36Sopenharmony_ci	if (status)
10062306a36Sopenharmony_ci		return status;
10162306a36Sopenharmony_ci	spin_lock(&registered_mechs_lock);
10262306a36Sopenharmony_ci	list_add_rcu(&gm->gm_list, &registered_mechs);
10362306a36Sopenharmony_ci	spin_unlock(&registered_mechs_lock);
10462306a36Sopenharmony_ci	dprintk("RPC:       registered gss mechanism %s\n", gm->gm_name);
10562306a36Sopenharmony_ci	return 0;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gss_mech_register);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/**
11062306a36Sopenharmony_ci * gss_mech_unregister - release a GSS mechanism
11162306a36Sopenharmony_ci * @gm: GSS mechanism handle
11262306a36Sopenharmony_ci *
11362306a36Sopenharmony_ci */
11462306a36Sopenharmony_civoid gss_mech_unregister(struct gss_api_mech *gm)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	spin_lock(&registered_mechs_lock);
11762306a36Sopenharmony_ci	list_del_rcu(&gm->gm_list);
11862306a36Sopenharmony_ci	spin_unlock(&registered_mechs_lock);
11962306a36Sopenharmony_ci	dprintk("RPC:       unregistered gss mechanism %s\n", gm->gm_name);
12062306a36Sopenharmony_ci	gss_mech_free(gm);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(gss_mech_unregister);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistruct gss_api_mech *gss_mech_get(struct gss_api_mech *gm)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	__module_get(gm->gm_owner);
12762306a36Sopenharmony_ci	return gm;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ciEXPORT_SYMBOL(gss_mech_get);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic struct gss_api_mech *
13262306a36Sopenharmony_ci_gss_mech_get_by_name(const char *name)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct gss_api_mech	*pos, *gm = NULL;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	rcu_read_lock();
13762306a36Sopenharmony_ci	list_for_each_entry_rcu(pos, &registered_mechs, gm_list) {
13862306a36Sopenharmony_ci		if (0 == strcmp(name, pos->gm_name)) {
13962306a36Sopenharmony_ci			if (try_module_get(pos->gm_owner))
14062306a36Sopenharmony_ci				gm = pos;
14162306a36Sopenharmony_ci			break;
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	rcu_read_unlock();
14562306a36Sopenharmony_ci	return gm;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistruct gss_api_mech * gss_mech_get_by_name(const char *name)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct gss_api_mech *gm = NULL;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	gm = _gss_mech_get_by_name(name);
15462306a36Sopenharmony_ci	if (!gm) {
15562306a36Sopenharmony_ci		request_module("rpc-auth-gss-%s", name);
15662306a36Sopenharmony_ci		gm = _gss_mech_get_by_name(name);
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	return gm;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistruct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct gss_api_mech	*pos, *gm = NULL;
16462306a36Sopenharmony_ci	char buf[32];
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0)
16762306a36Sopenharmony_ci		return NULL;
16862306a36Sopenharmony_ci	request_module("rpc-auth-gss-%s", buf);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	rcu_read_lock();
17162306a36Sopenharmony_ci	list_for_each_entry_rcu(pos, &registered_mechs, gm_list) {
17262306a36Sopenharmony_ci		if (obj->len == pos->gm_oid.len) {
17362306a36Sopenharmony_ci			if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) {
17462306a36Sopenharmony_ci				if (try_module_get(pos->gm_owner))
17562306a36Sopenharmony_ci					gm = pos;
17662306a36Sopenharmony_ci				break;
17762306a36Sopenharmony_ci			}
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci	rcu_read_unlock();
18162306a36Sopenharmony_ci	if (!gm)
18262306a36Sopenharmony_ci		trace_rpcgss_oid_to_mech(buf);
18362306a36Sopenharmony_ci	return gm;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic inline int
18762306a36Sopenharmony_cimech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	int i;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
19262306a36Sopenharmony_ci		if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
19362306a36Sopenharmony_ci			return 1;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	return 0;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct gss_api_mech *gm = NULL, *pos;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	rcu_read_lock();
20362306a36Sopenharmony_ci	list_for_each_entry_rcu(pos, &registered_mechs, gm_list) {
20462306a36Sopenharmony_ci		if (!mech_supports_pseudoflavor(pos, pseudoflavor))
20562306a36Sopenharmony_ci			continue;
20662306a36Sopenharmony_ci		if (try_module_get(pos->gm_owner))
20762306a36Sopenharmony_ci			gm = pos;
20862306a36Sopenharmony_ci		break;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci	rcu_read_unlock();
21162306a36Sopenharmony_ci	return gm;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistruct gss_api_mech *
21562306a36Sopenharmony_cigss_mech_get_by_pseudoflavor(u32 pseudoflavor)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct gss_api_mech *gm;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	gm = _gss_mech_get_by_pseudoflavor(pseudoflavor);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (!gm) {
22262306a36Sopenharmony_ci		request_module("rpc-auth-gss-%u", pseudoflavor);
22362306a36Sopenharmony_ci		gm = _gss_mech_get_by_pseudoflavor(pseudoflavor);
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci	return gm;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/**
22962306a36Sopenharmony_ci * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor
23062306a36Sopenharmony_ci * @gm: GSS mechanism handle
23162306a36Sopenharmony_ci * @qop: GSS quality-of-protection value
23262306a36Sopenharmony_ci * @service: GSS service value
23362306a36Sopenharmony_ci *
23462306a36Sopenharmony_ci * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found.
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_cirpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop,
23762306a36Sopenharmony_ci					 u32 service)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	int i;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
24262306a36Sopenharmony_ci		if (gm->gm_pfs[i].qop == qop &&
24362306a36Sopenharmony_ci		    gm->gm_pfs[i].service == service) {
24462306a36Sopenharmony_ci			return gm->gm_pfs[i].pseudoflavor;
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci	return RPC_AUTH_MAXFLAVOR;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/**
25162306a36Sopenharmony_ci * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple
25262306a36Sopenharmony_ci * @info: a GSS mech OID, quality of protection, and service value
25362306a36Sopenharmony_ci *
25462306a36Sopenharmony_ci * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is
25562306a36Sopenharmony_ci * not supported.
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cirpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	rpc_authflavor_t pseudoflavor;
26062306a36Sopenharmony_ci	struct gss_api_mech *gm;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	gm = gss_mech_get_by_OID(&info->oid);
26362306a36Sopenharmony_ci	if (gm == NULL)
26462306a36Sopenharmony_ci		return RPC_AUTH_MAXFLAVOR;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	gss_mech_put(gm);
26962306a36Sopenharmony_ci	return pseudoflavor;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/**
27362306a36Sopenharmony_ci * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor
27462306a36Sopenharmony_ci * @pseudoflavor: GSS pseudoflavor to match
27562306a36Sopenharmony_ci * @info: rpcsec_gss_info structure to fill in
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * Returns zero and fills in "info" if pseudoflavor matches a
27862306a36Sopenharmony_ci * supported mechanism.  Otherwise a negative errno is returned.
27962306a36Sopenharmony_ci */
28062306a36Sopenharmony_ciint gss_mech_flavor2info(rpc_authflavor_t pseudoflavor,
28162306a36Sopenharmony_ci			 struct rpcsec_gss_info *info)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct gss_api_mech *gm;
28462306a36Sopenharmony_ci	int i;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	gm = gss_mech_get_by_pseudoflavor(pseudoflavor);
28762306a36Sopenharmony_ci	if (gm == NULL)
28862306a36Sopenharmony_ci		return -ENOENT;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
29162306a36Sopenharmony_ci		if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) {
29262306a36Sopenharmony_ci			memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len);
29362306a36Sopenharmony_ci			info->oid.len = gm->gm_oid.len;
29462306a36Sopenharmony_ci			info->qop = gm->gm_pfs[i].qop;
29562306a36Sopenharmony_ci			info->service = gm->gm_pfs[i].service;
29662306a36Sopenharmony_ci			gss_mech_put(gm);
29762306a36Sopenharmony_ci			return 0;
29862306a36Sopenharmony_ci		}
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	gss_mech_put(gm);
30262306a36Sopenharmony_ci	return -ENOENT;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ciu32
30662306a36Sopenharmony_cigss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	int i;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
31162306a36Sopenharmony_ci		if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
31262306a36Sopenharmony_ci			return gm->gm_pfs[i].service;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ciEXPORT_SYMBOL(gss_pseudoflavor_to_service);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cibool
31962306a36Sopenharmony_cigss_pseudoflavor_to_datatouch(struct gss_api_mech *gm, u32 pseudoflavor)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	int i;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
32462306a36Sopenharmony_ci		if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
32562306a36Sopenharmony_ci			return gm->gm_pfs[i].datatouch;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci	return false;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cichar *
33162306a36Sopenharmony_cigss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	int i;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
33662306a36Sopenharmony_ci		if (gm->gm_pfs[i].service == service)
33762306a36Sopenharmony_ci			return gm->gm_pfs[i].auth_domain_name;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci	return NULL;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_civoid
34362306a36Sopenharmony_cigss_mech_put(struct gss_api_mech * gm)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	if (gm)
34662306a36Sopenharmony_ci		module_put(gm->gm_owner);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ciEXPORT_SYMBOL(gss_mech_put);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci/* The mech could probably be determined from the token instead, but it's just
35162306a36Sopenharmony_ci * as easy for now to pass it in. */
35262306a36Sopenharmony_ciint
35362306a36Sopenharmony_cigss_import_sec_context(const void *input_token, size_t bufsize,
35462306a36Sopenharmony_ci		       struct gss_api_mech	*mech,
35562306a36Sopenharmony_ci		       struct gss_ctx		**ctx_id,
35662306a36Sopenharmony_ci		       time64_t			*endtime,
35762306a36Sopenharmony_ci		       gfp_t gfp_mask)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	if (!(*ctx_id = kzalloc(sizeof(**ctx_id), gfp_mask)))
36062306a36Sopenharmony_ci		return -ENOMEM;
36162306a36Sopenharmony_ci	(*ctx_id)->mech_type = gss_mech_get(mech);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return mech->gm_ops->gss_import_sec_context(input_token, bufsize,
36462306a36Sopenharmony_ci						*ctx_id, endtime, gfp_mask);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/* gss_get_mic: compute a mic over message and return mic_token. */
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ciu32
37062306a36Sopenharmony_cigss_get_mic(struct gss_ctx	*context_handle,
37162306a36Sopenharmony_ci	    struct xdr_buf	*message,
37262306a36Sopenharmony_ci	    struct xdr_netobj	*mic_token)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	 return context_handle->mech_type->gm_ops
37562306a36Sopenharmony_ci		->gss_get_mic(context_handle,
37662306a36Sopenharmony_ci			      message,
37762306a36Sopenharmony_ci			      mic_token);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/* gss_verify_mic: check whether the provided mic_token verifies message. */
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ciu32
38362306a36Sopenharmony_cigss_verify_mic(struct gss_ctx		*context_handle,
38462306a36Sopenharmony_ci	       struct xdr_buf		*message,
38562306a36Sopenharmony_ci	       struct xdr_netobj	*mic_token)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	return context_handle->mech_type->gm_ops
38862306a36Sopenharmony_ci		->gss_verify_mic(context_handle,
38962306a36Sopenharmony_ci				 message,
39062306a36Sopenharmony_ci				 mic_token);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci/*
39462306a36Sopenharmony_ci * This function is called from both the client and server code.
39562306a36Sopenharmony_ci * Each makes guarantees about how much "slack" space is available
39662306a36Sopenharmony_ci * for the underlying function in "buf"'s head and tail while
39762306a36Sopenharmony_ci * performing the wrap.
39862306a36Sopenharmony_ci *
39962306a36Sopenharmony_ci * The client and server code allocate RPC_MAX_AUTH_SIZE extra
40062306a36Sopenharmony_ci * space in both the head and tail which is available for use by
40162306a36Sopenharmony_ci * the wrap function.
40262306a36Sopenharmony_ci *
40362306a36Sopenharmony_ci * Underlying functions should verify they do not use more than
40462306a36Sopenharmony_ci * RPC_MAX_AUTH_SIZE of extra space in either the head or tail
40562306a36Sopenharmony_ci * when performing the wrap.
40662306a36Sopenharmony_ci */
40762306a36Sopenharmony_ciu32
40862306a36Sopenharmony_cigss_wrap(struct gss_ctx	*ctx_id,
40962306a36Sopenharmony_ci	 int		offset,
41062306a36Sopenharmony_ci	 struct xdr_buf	*buf,
41162306a36Sopenharmony_ci	 struct page	**inpages)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	return ctx_id->mech_type->gm_ops
41462306a36Sopenharmony_ci		->gss_wrap(ctx_id, offset, buf, inpages);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ciu32
41862306a36Sopenharmony_cigss_unwrap(struct gss_ctx	*ctx_id,
41962306a36Sopenharmony_ci	   int			offset,
42062306a36Sopenharmony_ci	   int			len,
42162306a36Sopenharmony_ci	   struct xdr_buf	*buf)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	return ctx_id->mech_type->gm_ops
42462306a36Sopenharmony_ci		->gss_unwrap(ctx_id, offset, len, buf);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci/* gss_delete_sec_context: free all resources associated with context_handle.
42962306a36Sopenharmony_ci * Note this differs from the RFC 2744-specified prototype in that we don't
43062306a36Sopenharmony_ci * bother returning an output token, since it would never be used anyway. */
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciu32
43362306a36Sopenharmony_cigss_delete_sec_context(struct gss_ctx	**context_handle)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	dprintk("RPC:       gss_delete_sec_context deleting %p\n",
43662306a36Sopenharmony_ci			*context_handle);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (!*context_handle)
43962306a36Sopenharmony_ci		return GSS_S_NO_CONTEXT;
44062306a36Sopenharmony_ci	if ((*context_handle)->internal_ctx_id)
44162306a36Sopenharmony_ci		(*context_handle)->mech_type->gm_ops
44262306a36Sopenharmony_ci			->gss_delete_sec_context((*context_handle)
44362306a36Sopenharmony_ci							->internal_ctx_id);
44462306a36Sopenharmony_ci	gss_mech_put((*context_handle)->mech_type);
44562306a36Sopenharmony_ci	kfree(*context_handle);
44662306a36Sopenharmony_ci	*context_handle=NULL;
44762306a36Sopenharmony_ci	return GSS_S_COMPLETE;
44862306a36Sopenharmony_ci}
449