1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * linux/net/sunrpc/gss_rpc_upcall.c 4 * 5 * Copyright (C) 2012 Simo Sorce <simo@redhat.com> 6 */ 7 8 #include <linux/types.h> 9 #include <linux/un.h> 10 11 #include <linux/sunrpc/svcauth.h> 12 #include "gss_rpc_upcall.h" 13 14 #define GSSPROXY_SOCK_PATHNAME "/var/run/gssproxy.sock" 15 16 #define GSSPROXY_PROGRAM (400112u) 17 #define GSSPROXY_VERS_1 (1u) 18 19 /* 20 * Encoding/Decoding functions 21 */ 22 23 enum { 24 GSSX_NULL = 0, /* Unused */ 25 GSSX_INDICATE_MECHS = 1, 26 GSSX_GET_CALL_CONTEXT = 2, 27 GSSX_IMPORT_AND_CANON_NAME = 3, 28 GSSX_EXPORT_CRED = 4, 29 GSSX_IMPORT_CRED = 5, 30 GSSX_ACQUIRE_CRED = 6, 31 GSSX_STORE_CRED = 7, 32 GSSX_INIT_SEC_CONTEXT = 8, 33 GSSX_ACCEPT_SEC_CONTEXT = 9, 34 GSSX_RELEASE_HANDLE = 10, 35 GSSX_GET_MIC = 11, 36 GSSX_VERIFY = 12, 37 GSSX_WRAP = 13, 38 GSSX_UNWRAP = 14, 39 GSSX_WRAP_SIZE_LIMIT = 15, 40 }; 41 42 #define PROC(proc, name) \ 43 [GSSX_##proc] = { \ 44 .p_proc = GSSX_##proc, \ 45 .p_encode = gssx_enc_##name, \ 46 .p_decode = gssx_dec_##name, \ 47 .p_arglen = GSSX_ARG_##name##_sz, \ 48 .p_replen = GSSX_RES_##name##_sz, \ 49 .p_statidx = GSSX_##proc, \ 50 .p_name = #proc, \ 51 } 52 53 static const struct rpc_procinfo gssp_procedures[] = { 54 PROC(INDICATE_MECHS, indicate_mechs), 55 PROC(GET_CALL_CONTEXT, get_call_context), 56 PROC(IMPORT_AND_CANON_NAME, import_and_canon_name), 57 PROC(EXPORT_CRED, export_cred), 58 PROC(IMPORT_CRED, import_cred), 59 PROC(ACQUIRE_CRED, acquire_cred), 60 PROC(STORE_CRED, store_cred), 61 PROC(INIT_SEC_CONTEXT, init_sec_context), 62 PROC(ACCEPT_SEC_CONTEXT, accept_sec_context), 63 PROC(RELEASE_HANDLE, release_handle), 64 PROC(GET_MIC, get_mic), 65 PROC(VERIFY, verify), 66 PROC(WRAP, wrap), 67 PROC(UNWRAP, unwrap), 68 PROC(WRAP_SIZE_LIMIT, wrap_size_limit), 69 }; 70 71 72 73 /* 74 * Common transport functions 75 */ 76 77 static const struct rpc_program gssp_program; 78 79 static int gssp_rpc_create(struct net *net, struct rpc_clnt **_clnt) 80 { 81 static const struct sockaddr_un gssp_localaddr = { 82 .sun_family = AF_LOCAL, 83 .sun_path = GSSPROXY_SOCK_PATHNAME, 84 }; 85 struct rpc_create_args args = { 86 .net = net, 87 .protocol = XPRT_TRANSPORT_LOCAL, 88 .address = (struct sockaddr *)&gssp_localaddr, 89 .addrsize = sizeof(gssp_localaddr), 90 .servername = "localhost", 91 .program = &gssp_program, 92 .version = GSSPROXY_VERS_1, 93 .authflavor = RPC_AUTH_NULL, 94 /* 95 * Note we want connection to be done in the caller's 96 * filesystem namespace. We therefore turn off the idle 97 * timeout, which would result in reconnections being 98 * done without the correct namespace: 99 */ 100 .flags = RPC_CLNT_CREATE_NOPING | 101 RPC_CLNT_CREATE_NO_IDLE_TIMEOUT 102 }; 103 struct rpc_clnt *clnt; 104 int result = 0; 105 106 clnt = rpc_create(&args); 107 if (IS_ERR(clnt)) { 108 dprintk("RPC: failed to create AF_LOCAL gssproxy " 109 "client (errno %ld).\n", PTR_ERR(clnt)); 110 result = PTR_ERR(clnt); 111 *_clnt = NULL; 112 goto out; 113 } 114 115 dprintk("RPC: created new gssp local client (gssp_local_clnt: " 116 "%p)\n", clnt); 117 *_clnt = clnt; 118 119 out: 120 return result; 121 } 122 123 void init_gssp_clnt(struct sunrpc_net *sn) 124 { 125 mutex_init(&sn->gssp_lock); 126 sn->gssp_clnt = NULL; 127 } 128 129 int set_gssp_clnt(struct net *net) 130 { 131 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 132 struct rpc_clnt *clnt; 133 int ret; 134 135 mutex_lock(&sn->gssp_lock); 136 ret = gssp_rpc_create(net, &clnt); 137 if (!ret) { 138 if (sn->gssp_clnt) 139 rpc_shutdown_client(sn->gssp_clnt); 140 sn->gssp_clnt = clnt; 141 } 142 mutex_unlock(&sn->gssp_lock); 143 return ret; 144 } 145 146 void clear_gssp_clnt(struct sunrpc_net *sn) 147 { 148 mutex_lock(&sn->gssp_lock); 149 if (sn->gssp_clnt) { 150 rpc_shutdown_client(sn->gssp_clnt); 151 sn->gssp_clnt = NULL; 152 } 153 mutex_unlock(&sn->gssp_lock); 154 } 155 156 static struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn) 157 { 158 struct rpc_clnt *clnt; 159 160 mutex_lock(&sn->gssp_lock); 161 clnt = sn->gssp_clnt; 162 if (clnt) 163 atomic_inc(&clnt->cl_count); 164 mutex_unlock(&sn->gssp_lock); 165 return clnt; 166 } 167 168 static int gssp_call(struct net *net, struct rpc_message *msg) 169 { 170 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 171 struct rpc_clnt *clnt; 172 int status; 173 174 clnt = get_gssp_clnt(sn); 175 if (!clnt) 176 return -EIO; 177 status = rpc_call_sync(clnt, msg, 0); 178 if (status < 0) { 179 dprintk("gssp: rpc_call returned error %d\n", -status); 180 switch (status) { 181 case -EPROTONOSUPPORT: 182 status = -EINVAL; 183 break; 184 case -ECONNREFUSED: 185 case -ETIMEDOUT: 186 case -ENOTCONN: 187 status = -EAGAIN; 188 break; 189 case -ERESTARTSYS: 190 if (signalled ()) 191 status = -EINTR; 192 break; 193 default: 194 break; 195 } 196 } 197 rpc_release_client(clnt); 198 return status; 199 } 200 201 static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg) 202 { 203 int i; 204 205 for (i = 0; i < arg->npages && arg->pages[i]; i++) 206 __free_page(arg->pages[i]); 207 208 kfree(arg->pages); 209 } 210 211 static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg) 212 { 213 arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE); 214 arg->pages = kcalloc(arg->npages, sizeof(struct page *), GFP_KERNEL); 215 /* 216 * XXX: actual pages are allocated by xdr layer in 217 * xdr_partial_copy_from_skb. 218 */ 219 if (!arg->pages) 220 return -ENOMEM; 221 return 0; 222 } 223 224 static char *gssp_stringify(struct xdr_netobj *netobj) 225 { 226 return kmemdup_nul(netobj->data, netobj->len, GFP_KERNEL); 227 } 228 229 static void gssp_hostbased_service(char **principal) 230 { 231 char *c; 232 233 if (!*principal) 234 return; 235 236 /* terminate and remove realm part */ 237 c = strchr(*principal, '@'); 238 if (c) { 239 *c = '\0'; 240 241 /* change service-hostname delimiter */ 242 c = strchr(*principal, '/'); 243 if (c) 244 *c = '@'; 245 } 246 if (!c) { 247 /* not a service principal */ 248 kfree(*principal); 249 *principal = NULL; 250 } 251 } 252 253 /* 254 * Public functions 255 */ 256 257 /* numbers somewhat arbitrary but large enough for current needs */ 258 #define GSSX_MAX_OUT_HANDLE 128 259 #define GSSX_MAX_SRC_PRINC 256 260 #define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \ 261 GSSX_max_oid_sz + \ 262 GSSX_max_princ_sz + \ 263 sizeof(struct svc_cred)) 264 265 int gssp_accept_sec_context_upcall(struct net *net, 266 struct gssp_upcall_data *data) 267 { 268 struct gssx_ctx ctxh = { 269 .state = data->in_handle 270 }; 271 struct gssx_arg_accept_sec_context arg = { 272 .input_token = data->in_token, 273 }; 274 struct gssx_ctx rctxh = { 275 /* 276 * pass in the max length we expect for each of these 277 * buffers but let the xdr code kmalloc them: 278 */ 279 .exported_context_token.len = GSSX_max_output_handle_sz, 280 .mech.len = GSS_OID_MAX_LEN, 281 .targ_name.display_name.len = GSSX_max_princ_sz, 282 .src_name.display_name.len = GSSX_max_princ_sz 283 }; 284 struct gssx_res_accept_sec_context res = { 285 .context_handle = &rctxh, 286 .output_token = &data->out_token 287 }; 288 struct rpc_message msg = { 289 .rpc_proc = &gssp_procedures[GSSX_ACCEPT_SEC_CONTEXT], 290 .rpc_argp = &arg, 291 .rpc_resp = &res, 292 .rpc_cred = NULL, /* FIXME ? */ 293 }; 294 struct xdr_netobj client_name = { 0 , NULL }; 295 struct xdr_netobj target_name = { 0, NULL }; 296 int ret; 297 298 if (data->in_handle.len != 0) 299 arg.context_handle = &ctxh; 300 res.output_token->len = GSSX_max_output_token_sz; 301 302 ret = gssp_alloc_receive_pages(&arg); 303 if (ret) 304 return ret; 305 306 ret = gssp_call(net, &msg); 307 308 gssp_free_receive_pages(&arg); 309 310 /* we need to fetch all data even in case of error so 311 * that we can free special strctures is they have been allocated */ 312 data->major_status = res.status.major_status; 313 data->minor_status = res.status.minor_status; 314 if (res.context_handle) { 315 data->out_handle = rctxh.exported_context_token; 316 data->mech_oid.len = rctxh.mech.len; 317 if (rctxh.mech.data) { 318 memcpy(data->mech_oid.data, rctxh.mech.data, 319 data->mech_oid.len); 320 kfree(rctxh.mech.data); 321 } 322 client_name = rctxh.src_name.display_name; 323 target_name = rctxh.targ_name.display_name; 324 } 325 326 if (res.options.count == 1) { 327 gssx_buffer *value = &res.options.data[0].value; 328 /* Currently we only decode CREDS_VALUE, if we add 329 * anything else we'll have to loop and match on the 330 * option name */ 331 if (value->len == 1) { 332 /* steal group info from struct svc_cred */ 333 data->creds = *(struct svc_cred *)value->data; 334 data->found_creds = 1; 335 } 336 /* whether we use it or not, free data */ 337 kfree(value->data); 338 } 339 340 if (res.options.count != 0) { 341 kfree(res.options.data); 342 } 343 344 /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */ 345 if (data->found_creds) { 346 if (client_name.data) { 347 data->creds.cr_raw_principal = 348 gssp_stringify(&client_name); 349 data->creds.cr_principal = 350 gssp_stringify(&client_name); 351 gssp_hostbased_service(&data->creds.cr_principal); 352 } 353 if (target_name.data) { 354 data->creds.cr_targ_princ = 355 gssp_stringify(&target_name); 356 gssp_hostbased_service(&data->creds.cr_targ_princ); 357 } 358 } 359 kfree(client_name.data); 360 kfree(target_name.data); 361 362 return ret; 363 } 364 365 void gssp_free_upcall_data(struct gssp_upcall_data *data) 366 { 367 kfree(data->in_handle.data); 368 kfree(data->out_handle.data); 369 kfree(data->out_token.data); 370 free_svc_cred(&data->creds); 371 } 372 373 /* 374 * Initialization stuff 375 */ 376 static unsigned int gssp_version1_counts[ARRAY_SIZE(gssp_procedures)]; 377 static const struct rpc_version gssp_version1 = { 378 .number = GSSPROXY_VERS_1, 379 .nrprocs = ARRAY_SIZE(gssp_procedures), 380 .procs = gssp_procedures, 381 .counts = gssp_version1_counts, 382 }; 383 384 static const struct rpc_version *gssp_version[] = { 385 NULL, 386 &gssp_version1, 387 }; 388 389 static struct rpc_stat gssp_stats; 390 391 static const struct rpc_program gssp_program = { 392 .name = "gssproxy", 393 .number = GSSPROXY_PROGRAM, 394 .nrvers = ARRAY_SIZE(gssp_version), 395 .version = gssp_version, 396 .stats = &gssp_stats, 397 }; 398