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(®istered_mechs_lock); 1028c2ecf20Sopenharmony_ci list_add_rcu(&gm->gm_list, ®istered_mechs); 1038c2ecf20Sopenharmony_ci spin_unlock(®istered_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(®istered_mechs_lock); 1178c2ecf20Sopenharmony_ci list_del_rcu(&gm->gm_list); 1188c2ecf20Sopenharmony_ci spin_unlock(®istered_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, ®istered_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, ®istered_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, ®istered_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