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 unsigned 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 unsigned int i; 214 215 arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE); 216 arg->pages = kcalloc(arg->npages, sizeof(struct page *), GFP_KERNEL); 217 if (!arg->pages) 218 return -ENOMEM; 219 for (i = 0; i < arg->npages; i++) { 220 arg->pages[i] = alloc_page(GFP_KERNEL); 221 if (!arg->pages[i]) { 222 gssp_free_receive_pages(arg); 223 return -ENOMEM; 224 } 225 } 226 return 0; 227 } 228 229 static char *gssp_stringify(struct xdr_netobj *netobj) 230 { 231 return kmemdup_nul(netobj->data, netobj->len, GFP_KERNEL); 232 } 233 234 static void gssp_hostbased_service(char **principal) 235 { 236 char *c; 237 238 if (!*principal) 239 return; 240 241 /* terminate and remove realm part */ 242 c = strchr(*principal, '@'); 243 if (c) { 244 *c = '\0'; 245 246 /* change service-hostname delimiter */ 247 c = strchr(*principal, '/'); 248 if (c) 249 *c = '@'; 250 } 251 if (!c) { 252 /* not a service principal */ 253 kfree(*principal); 254 *principal = NULL; 255 } 256 } 257 258 /* 259 * Public functions 260 */ 261 262 /* numbers somewhat arbitrary but large enough for current needs */ 263 #define GSSX_MAX_OUT_HANDLE 128 264 #define GSSX_MAX_SRC_PRINC 256 265 #define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \ 266 GSSX_max_oid_sz + \ 267 GSSX_max_princ_sz + \ 268 sizeof(struct svc_cred)) 269 270 int gssp_accept_sec_context_upcall(struct net *net, 271 struct gssp_upcall_data *data) 272 { 273 struct gssx_ctx ctxh = { 274 .state = data->in_handle 275 }; 276 struct gssx_arg_accept_sec_context arg = { 277 .input_token = data->in_token, 278 }; 279 struct gssx_ctx rctxh = { 280 /* 281 * pass in the max length we expect for each of these 282 * buffers but let the xdr code kmalloc them: 283 */ 284 .exported_context_token.len = GSSX_max_output_handle_sz, 285 .mech.len = GSS_OID_MAX_LEN, 286 .targ_name.display_name.len = GSSX_max_princ_sz, 287 .src_name.display_name.len = GSSX_max_princ_sz 288 }; 289 struct gssx_res_accept_sec_context res = { 290 .context_handle = &rctxh, 291 .output_token = &data->out_token 292 }; 293 struct rpc_message msg = { 294 .rpc_proc = &gssp_procedures[GSSX_ACCEPT_SEC_CONTEXT], 295 .rpc_argp = &arg, 296 .rpc_resp = &res, 297 .rpc_cred = NULL, /* FIXME ? */ 298 }; 299 struct xdr_netobj client_name = { 0 , NULL }; 300 struct xdr_netobj target_name = { 0, NULL }; 301 int ret; 302 303 if (data->in_handle.len != 0) 304 arg.context_handle = &ctxh; 305 res.output_token->len = GSSX_max_output_token_sz; 306 307 ret = gssp_alloc_receive_pages(&arg); 308 if (ret) 309 return ret; 310 311 ret = gssp_call(net, &msg); 312 313 gssp_free_receive_pages(&arg); 314 315 /* we need to fetch all data even in case of error so 316 * that we can free special strctures is they have been allocated */ 317 data->major_status = res.status.major_status; 318 data->minor_status = res.status.minor_status; 319 if (res.context_handle) { 320 data->out_handle = rctxh.exported_context_token; 321 data->mech_oid.len = rctxh.mech.len; 322 if (rctxh.mech.data) { 323 memcpy(data->mech_oid.data, rctxh.mech.data, 324 data->mech_oid.len); 325 kfree(rctxh.mech.data); 326 } 327 client_name = rctxh.src_name.display_name; 328 target_name = rctxh.targ_name.display_name; 329 } 330 331 if (res.options.count == 1) { 332 gssx_buffer *value = &res.options.data[0].value; 333 /* Currently we only decode CREDS_VALUE, if we add 334 * anything else we'll have to loop and match on the 335 * option name */ 336 if (value->len == 1) { 337 /* steal group info from struct svc_cred */ 338 data->creds = *(struct svc_cred *)value->data; 339 data->found_creds = 1; 340 } 341 /* whether we use it or not, free data */ 342 kfree(value->data); 343 } 344 345 if (res.options.count != 0) { 346 kfree(res.options.data); 347 } 348 349 /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */ 350 if (data->found_creds) { 351 if (client_name.data) { 352 data->creds.cr_raw_principal = 353 gssp_stringify(&client_name); 354 data->creds.cr_principal = 355 gssp_stringify(&client_name); 356 gssp_hostbased_service(&data->creds.cr_principal); 357 } 358 if (target_name.data) { 359 data->creds.cr_targ_princ = 360 gssp_stringify(&target_name); 361 gssp_hostbased_service(&data->creds.cr_targ_princ); 362 } 363 } 364 kfree(client_name.data); 365 kfree(target_name.data); 366 367 return ret; 368 } 369 370 void gssp_free_upcall_data(struct gssp_upcall_data *data) 371 { 372 kfree(data->in_handle.data); 373 kfree(data->out_handle.data); 374 kfree(data->out_token.data); 375 free_svc_cred(&data->creds); 376 } 377 378 /* 379 * Initialization stuff 380 */ 381 static unsigned int gssp_version1_counts[ARRAY_SIZE(gssp_procedures)]; 382 static const struct rpc_version gssp_version1 = { 383 .number = GSSPROXY_VERS_1, 384 .nrprocs = ARRAY_SIZE(gssp_procedures), 385 .procs = gssp_procedures, 386 .counts = gssp_version1_counts, 387 }; 388 389 static const struct rpc_version *gssp_version[] = { 390 NULL, 391 &gssp_version1, 392 }; 393 394 static struct rpc_stat gssp_stats; 395 396 static const struct rpc_program gssp_program = { 397 .name = "gssproxy", 398 .number = GSSPROXY_PROGRAM, 399 .nrvers = ARRAY_SIZE(gssp_version), 400 .version = gssp_version, 401 .stats = &gssp_stats, 402 }; 403