root/net/sunrpc/auth_gss/gss_mech_switch.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gss_mech_free
  2. make_auth_domain_name
  3. gss_mech_svc_setup
  4. gss_mech_register
  5. gss_mech_unregister
  6. gss_mech_get
  7. _gss_mech_get_by_name
  8. gss_mech_get_by_name
  9. gss_mech_get_by_OID
  10. mech_supports_pseudoflavor
  11. _gss_mech_get_by_pseudoflavor
  12. gss_mech_get_by_pseudoflavor
  13. gss_mech_list_pseudoflavors
  14. gss_svc_to_pseudoflavor
  15. gss_mech_info2flavor
  16. gss_mech_flavor2info
  17. gss_pseudoflavor_to_service
  18. gss_pseudoflavor_to_datatouch
  19. gss_service_to_auth_domain_name
  20. gss_mech_put
  21. gss_import_sec_context
  22. gss_get_mic
  23. gss_verify_mic
  24. gss_wrap
  25. gss_unwrap
  26. gss_delete_sec_context

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

/* [<][>][^][v][top][bottom][index][help] */