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