1 // SPDX-License-Identifier: BSD-3-Clause 2 /* 3 * linux/net/sunrpc/gss_mech_switch.c 4 * 5 * Copyright (c) 2001 The Regents of the University of Michigan. 6 * All rights reserved. 7 * 8 * J. Bruce Fields <bfields@umich.edu> 9 */ 10 11 #include <linux/types.h> 12 #include <linux/slab.h> 13 #include <linux/module.h> 14 #include <linux/oid_registry.h> 15 #include <linux/sunrpc/msg_prot.h> 16 #include <linux/sunrpc/gss_asn1.h> 17 #include <linux/sunrpc/auth_gss.h> 18 #include <linux/sunrpc/svcauth_gss.h> 19 #include <linux/sunrpc/gss_err.h> 20 #include <linux/sunrpc/sched.h> 21 #include <linux/sunrpc/gss_api.h> 22 #include <linux/sunrpc/clnt.h> 23 #include <trace/events/rpcgss.h> 24 25 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 26 # define RPCDBG_FACILITY RPCDBG_AUTH 27 #endif 28 29 static LIST_HEAD(registered_mechs); 30 static DEFINE_SPINLOCK(registered_mechs_lock); 31 32 static void 33 gss_mech_free(struct gss_api_mech *gm) 34 { 35 struct pf_desc *pf; 36 int i; 37 38 for (i = 0; i < gm->gm_pf_num; i++) { 39 pf = &gm->gm_pfs[i]; 40 kfree(pf->auth_domain_name); 41 pf->auth_domain_name = NULL; 42 } 43 } 44 45 static inline char * 46 make_auth_domain_name(char *name) 47 { 48 static char *prefix = "gss/"; 49 char *new; 50 51 new = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL); 52 if (new) { 53 strcpy(new, prefix); 54 strcat(new, name); 55 } 56 return new; 57 } 58 59 static int 60 gss_mech_svc_setup(struct gss_api_mech *gm) 61 { 62 struct pf_desc *pf; 63 int i, status; 64 65 for (i = 0; i < gm->gm_pf_num; i++) { 66 pf = &gm->gm_pfs[i]; 67 pf->auth_domain_name = make_auth_domain_name(pf->name); 68 status = -ENOMEM; 69 if (pf->auth_domain_name == NULL) 70 goto out; 71 status = svcauth_gss_register_pseudoflavor(pf->pseudoflavor, 72 pf->auth_domain_name); 73 if (status) 74 goto out; 75 } 76 return 0; 77 out: 78 gss_mech_free(gm); 79 return status; 80 } 81 82 /** 83 * gss_mech_register - register a GSS mechanism 84 * @gm: GSS mechanism handle 85 * 86 * Returns zero if successful, or a negative errno. 87 */ 88 int gss_mech_register(struct gss_api_mech *gm) 89 { 90 int status; 91 92 status = gss_mech_svc_setup(gm); 93 if (status) 94 return status; 95 spin_lock(®istered_mechs_lock); 96 list_add_rcu(&gm->gm_list, ®istered_mechs); 97 spin_unlock(®istered_mechs_lock); 98 dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); 99 return 0; 100 } 101 EXPORT_SYMBOL_GPL(gss_mech_register); 102 103 /** 104 * gss_mech_unregister - release a GSS mechanism 105 * @gm: GSS mechanism handle 106 * 107 */ 108 void gss_mech_unregister(struct gss_api_mech *gm) 109 { 110 spin_lock(®istered_mechs_lock); 111 list_del_rcu(&gm->gm_list); 112 spin_unlock(®istered_mechs_lock); 113 dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); 114 gss_mech_free(gm); 115 } 116 EXPORT_SYMBOL_GPL(gss_mech_unregister); 117 118 struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm) 119 { 120 __module_get(gm->gm_owner); 121 return gm; 122 } 123 EXPORT_SYMBOL(gss_mech_get); 124 125 static struct gss_api_mech * 126 _gss_mech_get_by_name(const char *name) 127 { 128 struct gss_api_mech *pos, *gm = NULL; 129 130 rcu_read_lock(); 131 list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) { 132 if (0 == strcmp(name, pos->gm_name)) { 133 if (try_module_get(pos->gm_owner)) 134 gm = pos; 135 break; 136 } 137 } 138 rcu_read_unlock(); 139 return gm; 140 141 } 142 143 struct gss_api_mech * gss_mech_get_by_name(const char *name) 144 { 145 struct gss_api_mech *gm = NULL; 146 147 gm = _gss_mech_get_by_name(name); 148 if (!gm) { 149 request_module("rpc-auth-gss-%s", name); 150 gm = _gss_mech_get_by_name(name); 151 } 152 return gm; 153 } 154 155 struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) 156 { 157 struct gss_api_mech *pos, *gm = NULL; 158 char buf[32]; 159 160 if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0) 161 return NULL; 162 request_module("rpc-auth-gss-%s", buf); 163 164 rcu_read_lock(); 165 list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) { 166 if (obj->len == pos->gm_oid.len) { 167 if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) { 168 if (try_module_get(pos->gm_owner)) 169 gm = pos; 170 break; 171 } 172 } 173 } 174 rcu_read_unlock(); 175 if (!gm) 176 trace_rpcgss_oid_to_mech(buf); 177 return gm; 178 } 179 180 static inline int 181 mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) 182 { 183 int i; 184 185 for (i = 0; i < gm->gm_pf_num; i++) { 186 if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) 187 return 1; 188 } 189 return 0; 190 } 191 192 static struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor) 193 { 194 struct gss_api_mech *gm = NULL, *pos; 195 196 rcu_read_lock(); 197 list_for_each_entry_rcu(pos, ®istered_mechs, gm_list) { 198 if (!mech_supports_pseudoflavor(pos, pseudoflavor)) 199 continue; 200 if (try_module_get(pos->gm_owner)) 201 gm = pos; 202 break; 203 } 204 rcu_read_unlock(); 205 return gm; 206 } 207 208 struct gss_api_mech * 209 gss_mech_get_by_pseudoflavor(u32 pseudoflavor) 210 { 211 struct gss_api_mech *gm; 212 213 gm = _gss_mech_get_by_pseudoflavor(pseudoflavor); 214 215 if (!gm) { 216 request_module("rpc-auth-gss-%u", pseudoflavor); 217 gm = _gss_mech_get_by_pseudoflavor(pseudoflavor); 218 } 219 return gm; 220 } 221 222 /** 223 * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor 224 * @gm: GSS mechanism handle 225 * @qop: GSS quality-of-protection value 226 * @service: GSS service value 227 * 228 * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found. 229 */ 230 rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop, 231 u32 service) 232 { 233 int i; 234 235 for (i = 0; i < gm->gm_pf_num; i++) { 236 if (gm->gm_pfs[i].qop == qop && 237 gm->gm_pfs[i].service == service) { 238 return gm->gm_pfs[i].pseudoflavor; 239 } 240 } 241 return RPC_AUTH_MAXFLAVOR; 242 } 243 244 /** 245 * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple 246 * @info: a GSS mech OID, quality of protection, and service value 247 * 248 * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is 249 * not supported. 250 */ 251 rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info) 252 { 253 rpc_authflavor_t pseudoflavor; 254 struct gss_api_mech *gm; 255 256 gm = gss_mech_get_by_OID(&info->oid); 257 if (gm == NULL) 258 return RPC_AUTH_MAXFLAVOR; 259 260 pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service); 261 262 gss_mech_put(gm); 263 return pseudoflavor; 264 } 265 266 /** 267 * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor 268 * @pseudoflavor: GSS pseudoflavor to match 269 * @info: rpcsec_gss_info structure to fill in 270 * 271 * Returns zero and fills in "info" if pseudoflavor matches a 272 * supported mechanism. Otherwise a negative errno is returned. 273 */ 274 int gss_mech_flavor2info(rpc_authflavor_t pseudoflavor, 275 struct rpcsec_gss_info *info) 276 { 277 struct gss_api_mech *gm; 278 int i; 279 280 gm = gss_mech_get_by_pseudoflavor(pseudoflavor); 281 if (gm == NULL) 282 return -ENOENT; 283 284 for (i = 0; i < gm->gm_pf_num; i++) { 285 if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) { 286 memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len); 287 info->oid.len = gm->gm_oid.len; 288 info->qop = gm->gm_pfs[i].qop; 289 info->service = gm->gm_pfs[i].service; 290 gss_mech_put(gm); 291 return 0; 292 } 293 } 294 295 gss_mech_put(gm); 296 return -ENOENT; 297 } 298 299 u32 300 gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) 301 { 302 int i; 303 304 for (i = 0; i < gm->gm_pf_num; i++) { 305 if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) 306 return gm->gm_pfs[i].service; 307 } 308 return 0; 309 } 310 EXPORT_SYMBOL(gss_pseudoflavor_to_service); 311 312 bool 313 gss_pseudoflavor_to_datatouch(struct gss_api_mech *gm, u32 pseudoflavor) 314 { 315 int i; 316 317 for (i = 0; i < gm->gm_pf_num; i++) { 318 if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) 319 return gm->gm_pfs[i].datatouch; 320 } 321 return false; 322 } 323 324 char * 325 gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) 326 { 327 int i; 328 329 for (i = 0; i < gm->gm_pf_num; i++) { 330 if (gm->gm_pfs[i].service == service) 331 return gm->gm_pfs[i].auth_domain_name; 332 } 333 return NULL; 334 } 335 336 void 337 gss_mech_put(struct gss_api_mech * gm) 338 { 339 if (gm) 340 module_put(gm->gm_owner); 341 } 342 EXPORT_SYMBOL(gss_mech_put); 343 344 /* The mech could probably be determined from the token instead, but it's just 345 * as easy for now to pass it in. */ 346 int 347 gss_import_sec_context(const void *input_token, size_t bufsize, 348 struct gss_api_mech *mech, 349 struct gss_ctx **ctx_id, 350 time64_t *endtime, 351 gfp_t gfp_mask) 352 { 353 if (!(*ctx_id = kzalloc(sizeof(**ctx_id), gfp_mask))) 354 return -ENOMEM; 355 (*ctx_id)->mech_type = gss_mech_get(mech); 356 357 return mech->gm_ops->gss_import_sec_context(input_token, bufsize, 358 *ctx_id, endtime, gfp_mask); 359 } 360 361 /* gss_get_mic: compute a mic over message and return mic_token. */ 362 363 u32 364 gss_get_mic(struct gss_ctx *context_handle, 365 struct xdr_buf *message, 366 struct xdr_netobj *mic_token) 367 { 368 return context_handle->mech_type->gm_ops 369 ->gss_get_mic(context_handle, 370 message, 371 mic_token); 372 } 373 374 /* gss_verify_mic: check whether the provided mic_token verifies message. */ 375 376 u32 377 gss_verify_mic(struct gss_ctx *context_handle, 378 struct xdr_buf *message, 379 struct xdr_netobj *mic_token) 380 { 381 return context_handle->mech_type->gm_ops 382 ->gss_verify_mic(context_handle, 383 message, 384 mic_token); 385 } 386 387 /* 388 * This function is called from both the client and server code. 389 * Each makes guarantees about how much "slack" space is available 390 * for the underlying function in "buf"'s head and tail while 391 * performing the wrap. 392 * 393 * The client and server code allocate RPC_MAX_AUTH_SIZE extra 394 * space in both the head and tail which is available for use by 395 * the wrap function. 396 * 397 * Underlying functions should verify they do not use more than 398 * RPC_MAX_AUTH_SIZE of extra space in either the head or tail 399 * when performing the wrap. 400 */ 401 u32 402 gss_wrap(struct gss_ctx *ctx_id, 403 int offset, 404 struct xdr_buf *buf, 405 struct page **inpages) 406 { 407 return ctx_id->mech_type->gm_ops 408 ->gss_wrap(ctx_id, offset, buf, inpages); 409 } 410 411 u32 412 gss_unwrap(struct gss_ctx *ctx_id, 413 int offset, 414 struct xdr_buf *buf) 415 { 416 return ctx_id->mech_type->gm_ops 417 ->gss_unwrap(ctx_id, offset, buf); 418 } 419 420 421 /* gss_delete_sec_context: free all resources associated with context_handle. 422 * Note this differs from the RFC 2744-specified prototype in that we don't 423 * bother returning an output token, since it would never be used anyway. */ 424 425 u32 426 gss_delete_sec_context(struct gss_ctx **context_handle) 427 { 428 dprintk("RPC: gss_delete_sec_context deleting %p\n", 429 *context_handle); 430 431 if (!*context_handle) 432 return GSS_S_NO_CONTEXT; 433 if ((*context_handle)->internal_ctx_id) 434 (*context_handle)->mech_type->gm_ops 435 ->gss_delete_sec_context((*context_handle) 436 ->internal_ctx_id); 437 gss_mech_put((*context_handle)->mech_type); 438 kfree(*context_handle); 439 *context_handle=NULL; 440 return GSS_S_COMPLETE; 441 } 442