18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/net/sunrpc/gss_mech_switch.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (c) 2001 The Regents of the University of Michigan.
68c2ecf20Sopenharmony_ci *  All rights reserved.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  J. Bruce Fields   <bfields@umich.edu>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/types.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/oid_registry.h>
158c2ecf20Sopenharmony_ci#include <linux/sunrpc/msg_prot.h>
168c2ecf20Sopenharmony_ci#include <linux/sunrpc/gss_asn1.h>
178c2ecf20Sopenharmony_ci#include <linux/sunrpc/auth_gss.h>
188c2ecf20Sopenharmony_ci#include <linux/sunrpc/svcauth_gss.h>
198c2ecf20Sopenharmony_ci#include <linux/sunrpc/gss_err.h>
208c2ecf20Sopenharmony_ci#include <linux/sunrpc/sched.h>
218c2ecf20Sopenharmony_ci#include <linux/sunrpc/gss_api.h>
228c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h>
238c2ecf20Sopenharmony_ci#include <trace/events/rpcgss.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
268c2ecf20Sopenharmony_ci# define RPCDBG_FACILITY        RPCDBG_AUTH
278c2ecf20Sopenharmony_ci#endif
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic LIST_HEAD(registered_mechs);
308c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(registered_mechs_lock);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic void
338c2ecf20Sopenharmony_cigss_mech_free(struct gss_api_mech *gm)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct pf_desc *pf;
368c2ecf20Sopenharmony_ci	int i;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
398c2ecf20Sopenharmony_ci		pf = &gm->gm_pfs[i];
408c2ecf20Sopenharmony_ci		if (pf->domain)
418c2ecf20Sopenharmony_ci			auth_domain_put(pf->domain);
428c2ecf20Sopenharmony_ci		kfree(pf->auth_domain_name);
438c2ecf20Sopenharmony_ci		pf->auth_domain_name = NULL;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic inline char *
488c2ecf20Sopenharmony_cimake_auth_domain_name(char *name)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	static char	*prefix = "gss/";
518c2ecf20Sopenharmony_ci	char		*new;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	new = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL);
548c2ecf20Sopenharmony_ci	if (new) {
558c2ecf20Sopenharmony_ci		strcpy(new, prefix);
568c2ecf20Sopenharmony_ci		strcat(new, name);
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci	return new;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int
628c2ecf20Sopenharmony_cigss_mech_svc_setup(struct gss_api_mech *gm)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct auth_domain *dom;
658c2ecf20Sopenharmony_ci	struct pf_desc *pf;
668c2ecf20Sopenharmony_ci	int i, status;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
698c2ecf20Sopenharmony_ci		pf = &gm->gm_pfs[i];
708c2ecf20Sopenharmony_ci		pf->auth_domain_name = make_auth_domain_name(pf->name);
718c2ecf20Sopenharmony_ci		status = -ENOMEM;
728c2ecf20Sopenharmony_ci		if (pf->auth_domain_name == NULL)
738c2ecf20Sopenharmony_ci			goto out;
748c2ecf20Sopenharmony_ci		dom = svcauth_gss_register_pseudoflavor(
758c2ecf20Sopenharmony_ci			pf->pseudoflavor, pf->auth_domain_name);
768c2ecf20Sopenharmony_ci		if (IS_ERR(dom)) {
778c2ecf20Sopenharmony_ci			status = PTR_ERR(dom);
788c2ecf20Sopenharmony_ci			goto out;
798c2ecf20Sopenharmony_ci		}
808c2ecf20Sopenharmony_ci		pf->domain = dom;
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci	return 0;
838c2ecf20Sopenharmony_ciout:
848c2ecf20Sopenharmony_ci	gss_mech_free(gm);
858c2ecf20Sopenharmony_ci	return status;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/**
898c2ecf20Sopenharmony_ci * gss_mech_register - register a GSS mechanism
908c2ecf20Sopenharmony_ci * @gm: GSS mechanism handle
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci * Returns zero if successful, or a negative errno.
938c2ecf20Sopenharmony_ci */
948c2ecf20Sopenharmony_ciint gss_mech_register(struct gss_api_mech *gm)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	int status;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	status = gss_mech_svc_setup(gm);
998c2ecf20Sopenharmony_ci	if (status)
1008c2ecf20Sopenharmony_ci		return status;
1018c2ecf20Sopenharmony_ci	spin_lock(&registered_mechs_lock);
1028c2ecf20Sopenharmony_ci	list_add_rcu(&gm->gm_list, &registered_mechs);
1038c2ecf20Sopenharmony_ci	spin_unlock(&registered_mechs_lock);
1048c2ecf20Sopenharmony_ci	dprintk("RPC:       registered gss mechanism %s\n", gm->gm_name);
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(gss_mech_register);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/**
1108c2ecf20Sopenharmony_ci * gss_mech_unregister - release a GSS mechanism
1118c2ecf20Sopenharmony_ci * @gm: GSS mechanism handle
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_civoid gss_mech_unregister(struct gss_api_mech *gm)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	spin_lock(&registered_mechs_lock);
1178c2ecf20Sopenharmony_ci	list_del_rcu(&gm->gm_list);
1188c2ecf20Sopenharmony_ci	spin_unlock(&registered_mechs_lock);
1198c2ecf20Sopenharmony_ci	dprintk("RPC:       unregistered gss mechanism %s\n", gm->gm_name);
1208c2ecf20Sopenharmony_ci	gss_mech_free(gm);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(gss_mech_unregister);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistruct gss_api_mech *gss_mech_get(struct gss_api_mech *gm)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	__module_get(gm->gm_owner);
1278c2ecf20Sopenharmony_ci	return gm;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gss_mech_get);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic struct gss_api_mech *
1328c2ecf20Sopenharmony_ci_gss_mech_get_by_name(const char *name)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct gss_api_mech	*pos, *gm = NULL;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	rcu_read_lock();
1378c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(pos, &registered_mechs, gm_list) {
1388c2ecf20Sopenharmony_ci		if (0 == strcmp(name, pos->gm_name)) {
1398c2ecf20Sopenharmony_ci			if (try_module_get(pos->gm_owner))
1408c2ecf20Sopenharmony_ci				gm = pos;
1418c2ecf20Sopenharmony_ci			break;
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci	rcu_read_unlock();
1458c2ecf20Sopenharmony_ci	return gm;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistruct gss_api_mech * gss_mech_get_by_name(const char *name)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct gss_api_mech *gm = NULL;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	gm = _gss_mech_get_by_name(name);
1548c2ecf20Sopenharmony_ci	if (!gm) {
1558c2ecf20Sopenharmony_ci		request_module("rpc-auth-gss-%s", name);
1568c2ecf20Sopenharmony_ci		gm = _gss_mech_get_by_name(name);
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci	return gm;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistruct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct gss_api_mech	*pos, *gm = NULL;
1648c2ecf20Sopenharmony_ci	char buf[32];
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0)
1678c2ecf20Sopenharmony_ci		return NULL;
1688c2ecf20Sopenharmony_ci	request_module("rpc-auth-gss-%s", buf);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	rcu_read_lock();
1718c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(pos, &registered_mechs, gm_list) {
1728c2ecf20Sopenharmony_ci		if (obj->len == pos->gm_oid.len) {
1738c2ecf20Sopenharmony_ci			if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) {
1748c2ecf20Sopenharmony_ci				if (try_module_get(pos->gm_owner))
1758c2ecf20Sopenharmony_ci					gm = pos;
1768c2ecf20Sopenharmony_ci				break;
1778c2ecf20Sopenharmony_ci			}
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci	rcu_read_unlock();
1818c2ecf20Sopenharmony_ci	if (!gm)
1828c2ecf20Sopenharmony_ci		trace_rpcgss_oid_to_mech(buf);
1838c2ecf20Sopenharmony_ci	return gm;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic inline int
1878c2ecf20Sopenharmony_cimech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	int i;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
1928c2ecf20Sopenharmony_ci		if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
1938c2ecf20Sopenharmony_ci			return 1;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci	return 0;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct gss_api_mech *gm = NULL, *pos;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	rcu_read_lock();
2038c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(pos, &registered_mechs, gm_list) {
2048c2ecf20Sopenharmony_ci		if (!mech_supports_pseudoflavor(pos, pseudoflavor))
2058c2ecf20Sopenharmony_ci			continue;
2068c2ecf20Sopenharmony_ci		if (try_module_get(pos->gm_owner))
2078c2ecf20Sopenharmony_ci			gm = pos;
2088c2ecf20Sopenharmony_ci		break;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci	rcu_read_unlock();
2118c2ecf20Sopenharmony_ci	return gm;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistruct gss_api_mech *
2158c2ecf20Sopenharmony_cigss_mech_get_by_pseudoflavor(u32 pseudoflavor)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct gss_api_mech *gm;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	gm = _gss_mech_get_by_pseudoflavor(pseudoflavor);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (!gm) {
2228c2ecf20Sopenharmony_ci		request_module("rpc-auth-gss-%u", pseudoflavor);
2238c2ecf20Sopenharmony_ci		gm = _gss_mech_get_by_pseudoflavor(pseudoflavor);
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci	return gm;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci/**
2298c2ecf20Sopenharmony_ci * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor
2308c2ecf20Sopenharmony_ci * @gm: GSS mechanism handle
2318c2ecf20Sopenharmony_ci * @qop: GSS quality-of-protection value
2328c2ecf20Sopenharmony_ci * @service: GSS service value
2338c2ecf20Sopenharmony_ci *
2348c2ecf20Sopenharmony_ci * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found.
2358c2ecf20Sopenharmony_ci */
2368c2ecf20Sopenharmony_cirpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop,
2378c2ecf20Sopenharmony_ci					 u32 service)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	int i;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
2428c2ecf20Sopenharmony_ci		if (gm->gm_pfs[i].qop == qop &&
2438c2ecf20Sopenharmony_ci		    gm->gm_pfs[i].service == service) {
2448c2ecf20Sopenharmony_ci			return gm->gm_pfs[i].pseudoflavor;
2458c2ecf20Sopenharmony_ci		}
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci	return RPC_AUTH_MAXFLAVOR;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/**
2518c2ecf20Sopenharmony_ci * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple
2528c2ecf20Sopenharmony_ci * @info: a GSS mech OID, quality of protection, and service value
2538c2ecf20Sopenharmony_ci *
2548c2ecf20Sopenharmony_ci * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is
2558c2ecf20Sopenharmony_ci * not supported.
2568c2ecf20Sopenharmony_ci */
2578c2ecf20Sopenharmony_cirpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	rpc_authflavor_t pseudoflavor;
2608c2ecf20Sopenharmony_ci	struct gss_api_mech *gm;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	gm = gss_mech_get_by_OID(&info->oid);
2638c2ecf20Sopenharmony_ci	if (gm == NULL)
2648c2ecf20Sopenharmony_ci		return RPC_AUTH_MAXFLAVOR;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	gss_mech_put(gm);
2698c2ecf20Sopenharmony_ci	return pseudoflavor;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci/**
2738c2ecf20Sopenharmony_ci * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor
2748c2ecf20Sopenharmony_ci * @pseudoflavor: GSS pseudoflavor to match
2758c2ecf20Sopenharmony_ci * @info: rpcsec_gss_info structure to fill in
2768c2ecf20Sopenharmony_ci *
2778c2ecf20Sopenharmony_ci * Returns zero and fills in "info" if pseudoflavor matches a
2788c2ecf20Sopenharmony_ci * supported mechanism.  Otherwise a negative errno is returned.
2798c2ecf20Sopenharmony_ci */
2808c2ecf20Sopenharmony_ciint gss_mech_flavor2info(rpc_authflavor_t pseudoflavor,
2818c2ecf20Sopenharmony_ci			 struct rpcsec_gss_info *info)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct gss_api_mech *gm;
2848c2ecf20Sopenharmony_ci	int i;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	gm = gss_mech_get_by_pseudoflavor(pseudoflavor);
2878c2ecf20Sopenharmony_ci	if (gm == NULL)
2888c2ecf20Sopenharmony_ci		return -ENOENT;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
2918c2ecf20Sopenharmony_ci		if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) {
2928c2ecf20Sopenharmony_ci			memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len);
2938c2ecf20Sopenharmony_ci			info->oid.len = gm->gm_oid.len;
2948c2ecf20Sopenharmony_ci			info->qop = gm->gm_pfs[i].qop;
2958c2ecf20Sopenharmony_ci			info->service = gm->gm_pfs[i].service;
2968c2ecf20Sopenharmony_ci			gss_mech_put(gm);
2978c2ecf20Sopenharmony_ci			return 0;
2988c2ecf20Sopenharmony_ci		}
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	gss_mech_put(gm);
3028c2ecf20Sopenharmony_ci	return -ENOENT;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ciu32
3068c2ecf20Sopenharmony_cigss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	int i;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
3118c2ecf20Sopenharmony_ci		if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
3128c2ecf20Sopenharmony_ci			return gm->gm_pfs[i].service;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci	return 0;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gss_pseudoflavor_to_service);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cibool
3198c2ecf20Sopenharmony_cigss_pseudoflavor_to_datatouch(struct gss_api_mech *gm, u32 pseudoflavor)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	int i;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
3248c2ecf20Sopenharmony_ci		if (gm->gm_pfs[i].pseudoflavor == pseudoflavor)
3258c2ecf20Sopenharmony_ci			return gm->gm_pfs[i].datatouch;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci	return false;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cichar *
3318c2ecf20Sopenharmony_cigss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	int i;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	for (i = 0; i < gm->gm_pf_num; i++) {
3368c2ecf20Sopenharmony_ci		if (gm->gm_pfs[i].service == service)
3378c2ecf20Sopenharmony_ci			return gm->gm_pfs[i].auth_domain_name;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci	return NULL;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_civoid
3438c2ecf20Sopenharmony_cigss_mech_put(struct gss_api_mech * gm)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	if (gm)
3468c2ecf20Sopenharmony_ci		module_put(gm->gm_owner);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gss_mech_put);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci/* The mech could probably be determined from the token instead, but it's just
3518c2ecf20Sopenharmony_ci * as easy for now to pass it in. */
3528c2ecf20Sopenharmony_ciint
3538c2ecf20Sopenharmony_cigss_import_sec_context(const void *input_token, size_t bufsize,
3548c2ecf20Sopenharmony_ci		       struct gss_api_mech	*mech,
3558c2ecf20Sopenharmony_ci		       struct gss_ctx		**ctx_id,
3568c2ecf20Sopenharmony_ci		       time64_t			*endtime,
3578c2ecf20Sopenharmony_ci		       gfp_t gfp_mask)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	if (!(*ctx_id = kzalloc(sizeof(**ctx_id), gfp_mask)))
3608c2ecf20Sopenharmony_ci		return -ENOMEM;
3618c2ecf20Sopenharmony_ci	(*ctx_id)->mech_type = gss_mech_get(mech);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return mech->gm_ops->gss_import_sec_context(input_token, bufsize,
3648c2ecf20Sopenharmony_ci						*ctx_id, endtime, gfp_mask);
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/* gss_get_mic: compute a mic over message and return mic_token. */
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ciu32
3708c2ecf20Sopenharmony_cigss_get_mic(struct gss_ctx	*context_handle,
3718c2ecf20Sopenharmony_ci	    struct xdr_buf	*message,
3728c2ecf20Sopenharmony_ci	    struct xdr_netobj	*mic_token)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	 return context_handle->mech_type->gm_ops
3758c2ecf20Sopenharmony_ci		->gss_get_mic(context_handle,
3768c2ecf20Sopenharmony_ci			      message,
3778c2ecf20Sopenharmony_ci			      mic_token);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/* gss_verify_mic: check whether the provided mic_token verifies message. */
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ciu32
3838c2ecf20Sopenharmony_cigss_verify_mic(struct gss_ctx		*context_handle,
3848c2ecf20Sopenharmony_ci	       struct xdr_buf		*message,
3858c2ecf20Sopenharmony_ci	       struct xdr_netobj	*mic_token)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	return context_handle->mech_type->gm_ops
3888c2ecf20Sopenharmony_ci		->gss_verify_mic(context_handle,
3898c2ecf20Sopenharmony_ci				 message,
3908c2ecf20Sopenharmony_ci				 mic_token);
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci/*
3948c2ecf20Sopenharmony_ci * This function is called from both the client and server code.
3958c2ecf20Sopenharmony_ci * Each makes guarantees about how much "slack" space is available
3968c2ecf20Sopenharmony_ci * for the underlying function in "buf"'s head and tail while
3978c2ecf20Sopenharmony_ci * performing the wrap.
3988c2ecf20Sopenharmony_ci *
3998c2ecf20Sopenharmony_ci * The client and server code allocate RPC_MAX_AUTH_SIZE extra
4008c2ecf20Sopenharmony_ci * space in both the head and tail which is available for use by
4018c2ecf20Sopenharmony_ci * the wrap function.
4028c2ecf20Sopenharmony_ci *
4038c2ecf20Sopenharmony_ci * Underlying functions should verify they do not use more than
4048c2ecf20Sopenharmony_ci * RPC_MAX_AUTH_SIZE of extra space in either the head or tail
4058c2ecf20Sopenharmony_ci * when performing the wrap.
4068c2ecf20Sopenharmony_ci */
4078c2ecf20Sopenharmony_ciu32
4088c2ecf20Sopenharmony_cigss_wrap(struct gss_ctx	*ctx_id,
4098c2ecf20Sopenharmony_ci	 int		offset,
4108c2ecf20Sopenharmony_ci	 struct xdr_buf	*buf,
4118c2ecf20Sopenharmony_ci	 struct page	**inpages)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	return ctx_id->mech_type->gm_ops
4148c2ecf20Sopenharmony_ci		->gss_wrap(ctx_id, offset, buf, inpages);
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ciu32
4188c2ecf20Sopenharmony_cigss_unwrap(struct gss_ctx	*ctx_id,
4198c2ecf20Sopenharmony_ci	   int			offset,
4208c2ecf20Sopenharmony_ci	   int			len,
4218c2ecf20Sopenharmony_ci	   struct xdr_buf	*buf)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	return ctx_id->mech_type->gm_ops
4248c2ecf20Sopenharmony_ci		->gss_unwrap(ctx_id, offset, len, buf);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci/* gss_delete_sec_context: free all resources associated with context_handle.
4298c2ecf20Sopenharmony_ci * Note this differs from the RFC 2744-specified prototype in that we don't
4308c2ecf20Sopenharmony_ci * bother returning an output token, since it would never be used anyway. */
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ciu32
4338c2ecf20Sopenharmony_cigss_delete_sec_context(struct gss_ctx	**context_handle)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	dprintk("RPC:       gss_delete_sec_context deleting %p\n",
4368c2ecf20Sopenharmony_ci			*context_handle);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (!*context_handle)
4398c2ecf20Sopenharmony_ci		return GSS_S_NO_CONTEXT;
4408c2ecf20Sopenharmony_ci	if ((*context_handle)->internal_ctx_id)
4418c2ecf20Sopenharmony_ci		(*context_handle)->mech_type->gm_ops
4428c2ecf20Sopenharmony_ci			->gss_delete_sec_context((*context_handle)
4438c2ecf20Sopenharmony_ci							->internal_ctx_id);
4448c2ecf20Sopenharmony_ci	gss_mech_put((*context_handle)->mech_type);
4458c2ecf20Sopenharmony_ci	kfree(*context_handle);
4468c2ecf20Sopenharmony_ci	*context_handle=NULL;
4478c2ecf20Sopenharmony_ci	return GSS_S_COMPLETE;
4488c2ecf20Sopenharmony_ci}
449