162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/net/sunrpc/gss_rpc_upcall.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Simo Sorce <simo@redhat.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci#include <linux/un.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/sunrpc/svcauth.h> 1262306a36Sopenharmony_ci#include "gss_rpc_upcall.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define GSSPROXY_SOCK_PATHNAME "/var/run/gssproxy.sock" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define GSSPROXY_PROGRAM (400112u) 1762306a36Sopenharmony_ci#define GSSPROXY_VERS_1 (1u) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Encoding/Decoding functions 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cienum { 2462306a36Sopenharmony_ci GSSX_NULL = 0, /* Unused */ 2562306a36Sopenharmony_ci GSSX_INDICATE_MECHS = 1, 2662306a36Sopenharmony_ci GSSX_GET_CALL_CONTEXT = 2, 2762306a36Sopenharmony_ci GSSX_IMPORT_AND_CANON_NAME = 3, 2862306a36Sopenharmony_ci GSSX_EXPORT_CRED = 4, 2962306a36Sopenharmony_ci GSSX_IMPORT_CRED = 5, 3062306a36Sopenharmony_ci GSSX_ACQUIRE_CRED = 6, 3162306a36Sopenharmony_ci GSSX_STORE_CRED = 7, 3262306a36Sopenharmony_ci GSSX_INIT_SEC_CONTEXT = 8, 3362306a36Sopenharmony_ci GSSX_ACCEPT_SEC_CONTEXT = 9, 3462306a36Sopenharmony_ci GSSX_RELEASE_HANDLE = 10, 3562306a36Sopenharmony_ci GSSX_GET_MIC = 11, 3662306a36Sopenharmony_ci GSSX_VERIFY = 12, 3762306a36Sopenharmony_ci GSSX_WRAP = 13, 3862306a36Sopenharmony_ci GSSX_UNWRAP = 14, 3962306a36Sopenharmony_ci GSSX_WRAP_SIZE_LIMIT = 15, 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define PROC(proc, name) \ 4362306a36Sopenharmony_ci[GSSX_##proc] = { \ 4462306a36Sopenharmony_ci .p_proc = GSSX_##proc, \ 4562306a36Sopenharmony_ci .p_encode = gssx_enc_##name, \ 4662306a36Sopenharmony_ci .p_decode = gssx_dec_##name, \ 4762306a36Sopenharmony_ci .p_arglen = GSSX_ARG_##name##_sz, \ 4862306a36Sopenharmony_ci .p_replen = GSSX_RES_##name##_sz, \ 4962306a36Sopenharmony_ci .p_statidx = GSSX_##proc, \ 5062306a36Sopenharmony_ci .p_name = #proc, \ 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const struct rpc_procinfo gssp_procedures[] = { 5462306a36Sopenharmony_ci PROC(INDICATE_MECHS, indicate_mechs), 5562306a36Sopenharmony_ci PROC(GET_CALL_CONTEXT, get_call_context), 5662306a36Sopenharmony_ci PROC(IMPORT_AND_CANON_NAME, import_and_canon_name), 5762306a36Sopenharmony_ci PROC(EXPORT_CRED, export_cred), 5862306a36Sopenharmony_ci PROC(IMPORT_CRED, import_cred), 5962306a36Sopenharmony_ci PROC(ACQUIRE_CRED, acquire_cred), 6062306a36Sopenharmony_ci PROC(STORE_CRED, store_cred), 6162306a36Sopenharmony_ci PROC(INIT_SEC_CONTEXT, init_sec_context), 6262306a36Sopenharmony_ci PROC(ACCEPT_SEC_CONTEXT, accept_sec_context), 6362306a36Sopenharmony_ci PROC(RELEASE_HANDLE, release_handle), 6462306a36Sopenharmony_ci PROC(GET_MIC, get_mic), 6562306a36Sopenharmony_ci PROC(VERIFY, verify), 6662306a36Sopenharmony_ci PROC(WRAP, wrap), 6762306a36Sopenharmony_ci PROC(UNWRAP, unwrap), 6862306a36Sopenharmony_ci PROC(WRAP_SIZE_LIMIT, wrap_size_limit), 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * Common transport functions 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct rpc_program gssp_program; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int gssp_rpc_create(struct net *net, struct rpc_clnt **_clnt) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci static const struct sockaddr_un gssp_localaddr = { 8262306a36Sopenharmony_ci .sun_family = AF_LOCAL, 8362306a36Sopenharmony_ci .sun_path = GSSPROXY_SOCK_PATHNAME, 8462306a36Sopenharmony_ci }; 8562306a36Sopenharmony_ci struct rpc_create_args args = { 8662306a36Sopenharmony_ci .net = net, 8762306a36Sopenharmony_ci .protocol = XPRT_TRANSPORT_LOCAL, 8862306a36Sopenharmony_ci .address = (struct sockaddr *)&gssp_localaddr, 8962306a36Sopenharmony_ci .addrsize = sizeof(gssp_localaddr), 9062306a36Sopenharmony_ci .servername = "localhost", 9162306a36Sopenharmony_ci .program = &gssp_program, 9262306a36Sopenharmony_ci .version = GSSPROXY_VERS_1, 9362306a36Sopenharmony_ci .authflavor = RPC_AUTH_NULL, 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * Note we want connection to be done in the caller's 9662306a36Sopenharmony_ci * filesystem namespace. We therefore turn off the idle 9762306a36Sopenharmony_ci * timeout, which would result in reconnections being 9862306a36Sopenharmony_ci * done without the correct namespace: 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci .flags = RPC_CLNT_CREATE_NOPING | 10162306a36Sopenharmony_ci RPC_CLNT_CREATE_CONNECTED | 10262306a36Sopenharmony_ci RPC_CLNT_CREATE_NO_IDLE_TIMEOUT 10362306a36Sopenharmony_ci }; 10462306a36Sopenharmony_ci struct rpc_clnt *clnt; 10562306a36Sopenharmony_ci int result = 0; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci clnt = rpc_create(&args); 10862306a36Sopenharmony_ci if (IS_ERR(clnt)) { 10962306a36Sopenharmony_ci dprintk("RPC: failed to create AF_LOCAL gssproxy " 11062306a36Sopenharmony_ci "client (errno %ld).\n", PTR_ERR(clnt)); 11162306a36Sopenharmony_ci result = PTR_ERR(clnt); 11262306a36Sopenharmony_ci *_clnt = NULL; 11362306a36Sopenharmony_ci goto out; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci dprintk("RPC: created new gssp local client (gssp_local_clnt: " 11762306a36Sopenharmony_ci "%p)\n", clnt); 11862306a36Sopenharmony_ci *_clnt = clnt; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciout: 12162306a36Sopenharmony_ci return result; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_civoid init_gssp_clnt(struct sunrpc_net *sn) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci mutex_init(&sn->gssp_lock); 12762306a36Sopenharmony_ci sn->gssp_clnt = NULL; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciint set_gssp_clnt(struct net *net) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 13362306a36Sopenharmony_ci struct rpc_clnt *clnt; 13462306a36Sopenharmony_ci int ret; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci mutex_lock(&sn->gssp_lock); 13762306a36Sopenharmony_ci ret = gssp_rpc_create(net, &clnt); 13862306a36Sopenharmony_ci if (!ret) { 13962306a36Sopenharmony_ci if (sn->gssp_clnt) 14062306a36Sopenharmony_ci rpc_shutdown_client(sn->gssp_clnt); 14162306a36Sopenharmony_ci sn->gssp_clnt = clnt; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci mutex_unlock(&sn->gssp_lock); 14462306a36Sopenharmony_ci return ret; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_civoid clear_gssp_clnt(struct sunrpc_net *sn) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci mutex_lock(&sn->gssp_lock); 15062306a36Sopenharmony_ci if (sn->gssp_clnt) { 15162306a36Sopenharmony_ci rpc_shutdown_client(sn->gssp_clnt); 15262306a36Sopenharmony_ci sn->gssp_clnt = NULL; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci mutex_unlock(&sn->gssp_lock); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct rpc_clnt *clnt; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci mutex_lock(&sn->gssp_lock); 16262306a36Sopenharmony_ci clnt = sn->gssp_clnt; 16362306a36Sopenharmony_ci if (clnt) 16462306a36Sopenharmony_ci refcount_inc(&clnt->cl_count); 16562306a36Sopenharmony_ci mutex_unlock(&sn->gssp_lock); 16662306a36Sopenharmony_ci return clnt; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int gssp_call(struct net *net, struct rpc_message *msg) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 17262306a36Sopenharmony_ci struct rpc_clnt *clnt; 17362306a36Sopenharmony_ci int status; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci clnt = get_gssp_clnt(sn); 17662306a36Sopenharmony_ci if (!clnt) 17762306a36Sopenharmony_ci return -EIO; 17862306a36Sopenharmony_ci status = rpc_call_sync(clnt, msg, 0); 17962306a36Sopenharmony_ci if (status < 0) { 18062306a36Sopenharmony_ci dprintk("gssp: rpc_call returned error %d\n", -status); 18162306a36Sopenharmony_ci switch (status) { 18262306a36Sopenharmony_ci case -EPROTONOSUPPORT: 18362306a36Sopenharmony_ci status = -EINVAL; 18462306a36Sopenharmony_ci break; 18562306a36Sopenharmony_ci case -ECONNREFUSED: 18662306a36Sopenharmony_ci case -ETIMEDOUT: 18762306a36Sopenharmony_ci case -ENOTCONN: 18862306a36Sopenharmony_ci status = -EAGAIN; 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci case -ERESTARTSYS: 19162306a36Sopenharmony_ci if (signalled ()) 19262306a36Sopenharmony_ci status = -EINTR; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci default: 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci rpc_release_client(clnt); 19962306a36Sopenharmony_ci return status; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci unsigned int i; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci for (i = 0; i < arg->npages && arg->pages[i]; i++) 20762306a36Sopenharmony_ci __free_page(arg->pages[i]); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci kfree(arg->pages); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci unsigned int i; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE); 21762306a36Sopenharmony_ci arg->pages = kcalloc(arg->npages, sizeof(struct page *), GFP_KERNEL); 21862306a36Sopenharmony_ci if (!arg->pages) 21962306a36Sopenharmony_ci return -ENOMEM; 22062306a36Sopenharmony_ci for (i = 0; i < arg->npages; i++) { 22162306a36Sopenharmony_ci arg->pages[i] = alloc_page(GFP_KERNEL); 22262306a36Sopenharmony_ci if (!arg->pages[i]) { 22362306a36Sopenharmony_ci gssp_free_receive_pages(arg); 22462306a36Sopenharmony_ci return -ENOMEM; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic char *gssp_stringify(struct xdr_netobj *netobj) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci return kmemdup_nul(netobj->data, netobj->len, GFP_KERNEL); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void gssp_hostbased_service(char **principal) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci char *c; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (!*principal) 24062306a36Sopenharmony_ci return; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* terminate and remove realm part */ 24362306a36Sopenharmony_ci c = strchr(*principal, '@'); 24462306a36Sopenharmony_ci if (c) { 24562306a36Sopenharmony_ci *c = '\0'; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* change service-hostname delimiter */ 24862306a36Sopenharmony_ci c = strchr(*principal, '/'); 24962306a36Sopenharmony_ci if (c) 25062306a36Sopenharmony_ci *c = '@'; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci if (!c) { 25362306a36Sopenharmony_ci /* not a service principal */ 25462306a36Sopenharmony_ci kfree(*principal); 25562306a36Sopenharmony_ci *principal = NULL; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/* 26062306a36Sopenharmony_ci * Public functions 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* numbers somewhat arbitrary but large enough for current needs */ 26462306a36Sopenharmony_ci#define GSSX_MAX_OUT_HANDLE 128 26562306a36Sopenharmony_ci#define GSSX_MAX_SRC_PRINC 256 26662306a36Sopenharmony_ci#define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \ 26762306a36Sopenharmony_ci GSSX_max_oid_sz + \ 26862306a36Sopenharmony_ci GSSX_max_princ_sz + \ 26962306a36Sopenharmony_ci sizeof(struct svc_cred)) 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ciint gssp_accept_sec_context_upcall(struct net *net, 27262306a36Sopenharmony_ci struct gssp_upcall_data *data) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct gssx_ctx ctxh = { 27562306a36Sopenharmony_ci .state = data->in_handle 27662306a36Sopenharmony_ci }; 27762306a36Sopenharmony_ci struct gssx_arg_accept_sec_context arg = { 27862306a36Sopenharmony_ci .input_token = data->in_token, 27962306a36Sopenharmony_ci }; 28062306a36Sopenharmony_ci struct gssx_ctx rctxh = { 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * pass in the max length we expect for each of these 28362306a36Sopenharmony_ci * buffers but let the xdr code kmalloc them: 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci .exported_context_token.len = GSSX_max_output_handle_sz, 28662306a36Sopenharmony_ci .mech.len = GSS_OID_MAX_LEN, 28762306a36Sopenharmony_ci .targ_name.display_name.len = GSSX_max_princ_sz, 28862306a36Sopenharmony_ci .src_name.display_name.len = GSSX_max_princ_sz 28962306a36Sopenharmony_ci }; 29062306a36Sopenharmony_ci struct gssx_res_accept_sec_context res = { 29162306a36Sopenharmony_ci .context_handle = &rctxh, 29262306a36Sopenharmony_ci .output_token = &data->out_token 29362306a36Sopenharmony_ci }; 29462306a36Sopenharmony_ci struct rpc_message msg = { 29562306a36Sopenharmony_ci .rpc_proc = &gssp_procedures[GSSX_ACCEPT_SEC_CONTEXT], 29662306a36Sopenharmony_ci .rpc_argp = &arg, 29762306a36Sopenharmony_ci .rpc_resp = &res, 29862306a36Sopenharmony_ci .rpc_cred = NULL, /* FIXME ? */ 29962306a36Sopenharmony_ci }; 30062306a36Sopenharmony_ci struct xdr_netobj client_name = { 0 , NULL }; 30162306a36Sopenharmony_ci struct xdr_netobj target_name = { 0, NULL }; 30262306a36Sopenharmony_ci int ret; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (data->in_handle.len != 0) 30562306a36Sopenharmony_ci arg.context_handle = &ctxh; 30662306a36Sopenharmony_ci res.output_token->len = GSSX_max_output_token_sz; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci ret = gssp_alloc_receive_pages(&arg); 30962306a36Sopenharmony_ci if (ret) 31062306a36Sopenharmony_ci return ret; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ret = gssp_call(net, &msg); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci gssp_free_receive_pages(&arg); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* we need to fetch all data even in case of error so 31762306a36Sopenharmony_ci * that we can free special strctures is they have been allocated */ 31862306a36Sopenharmony_ci data->major_status = res.status.major_status; 31962306a36Sopenharmony_ci data->minor_status = res.status.minor_status; 32062306a36Sopenharmony_ci if (res.context_handle) { 32162306a36Sopenharmony_ci data->out_handle = rctxh.exported_context_token; 32262306a36Sopenharmony_ci data->mech_oid.len = rctxh.mech.len; 32362306a36Sopenharmony_ci if (rctxh.mech.data) { 32462306a36Sopenharmony_ci memcpy(data->mech_oid.data, rctxh.mech.data, 32562306a36Sopenharmony_ci data->mech_oid.len); 32662306a36Sopenharmony_ci kfree(rctxh.mech.data); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci client_name = rctxh.src_name.display_name; 32962306a36Sopenharmony_ci target_name = rctxh.targ_name.display_name; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (res.options.count == 1) { 33362306a36Sopenharmony_ci gssx_buffer *value = &res.options.data[0].value; 33462306a36Sopenharmony_ci /* Currently we only decode CREDS_VALUE, if we add 33562306a36Sopenharmony_ci * anything else we'll have to loop and match on the 33662306a36Sopenharmony_ci * option name */ 33762306a36Sopenharmony_ci if (value->len == 1) { 33862306a36Sopenharmony_ci /* steal group info from struct svc_cred */ 33962306a36Sopenharmony_ci data->creds = *(struct svc_cred *)value->data; 34062306a36Sopenharmony_ci data->found_creds = 1; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci /* whether we use it or not, free data */ 34362306a36Sopenharmony_ci kfree(value->data); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (res.options.count != 0) { 34762306a36Sopenharmony_ci kfree(res.options.data); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */ 35162306a36Sopenharmony_ci if (data->found_creds) { 35262306a36Sopenharmony_ci if (client_name.data) { 35362306a36Sopenharmony_ci data->creds.cr_raw_principal = 35462306a36Sopenharmony_ci gssp_stringify(&client_name); 35562306a36Sopenharmony_ci data->creds.cr_principal = 35662306a36Sopenharmony_ci gssp_stringify(&client_name); 35762306a36Sopenharmony_ci gssp_hostbased_service(&data->creds.cr_principal); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci if (target_name.data) { 36062306a36Sopenharmony_ci data->creds.cr_targ_princ = 36162306a36Sopenharmony_ci gssp_stringify(&target_name); 36262306a36Sopenharmony_ci gssp_hostbased_service(&data->creds.cr_targ_princ); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci kfree(client_name.data); 36662306a36Sopenharmony_ci kfree(target_name.data); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return ret; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_civoid gssp_free_upcall_data(struct gssp_upcall_data *data) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci kfree(data->in_handle.data); 37462306a36Sopenharmony_ci kfree(data->out_handle.data); 37562306a36Sopenharmony_ci kfree(data->out_token.data); 37662306a36Sopenharmony_ci free_svc_cred(&data->creds); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* 38062306a36Sopenharmony_ci * Initialization stuff 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistatic unsigned int gssp_version1_counts[ARRAY_SIZE(gssp_procedures)]; 38362306a36Sopenharmony_cistatic const struct rpc_version gssp_version1 = { 38462306a36Sopenharmony_ci .number = GSSPROXY_VERS_1, 38562306a36Sopenharmony_ci .nrprocs = ARRAY_SIZE(gssp_procedures), 38662306a36Sopenharmony_ci .procs = gssp_procedures, 38762306a36Sopenharmony_ci .counts = gssp_version1_counts, 38862306a36Sopenharmony_ci}; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic const struct rpc_version *gssp_version[] = { 39162306a36Sopenharmony_ci NULL, 39262306a36Sopenharmony_ci &gssp_version1, 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic struct rpc_stat gssp_stats; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic const struct rpc_program gssp_program = { 39862306a36Sopenharmony_ci .name = "gssproxy", 39962306a36Sopenharmony_ci .number = GSSPROXY_PROGRAM, 40062306a36Sopenharmony_ci .nrvers = ARRAY_SIZE(gssp_version), 40162306a36Sopenharmony_ci .version = gssp_version, 40262306a36Sopenharmony_ci .stats = &gssp_stats, 40362306a36Sopenharmony_ci}; 404