gss_krb5_mech.c (16680B)
1// SPDX-License-Identifier: BSD-3-Clause 2/* 3 * linux/net/sunrpc/gss_krb5_mech.c 4 * 5 * Copyright (c) 2001-2008 The Regents of the University of Michigan. 6 * All rights reserved. 7 * 8 * Andy Adamson <andros@umich.edu> 9 * J. Bruce Fields <bfields@umich.edu> 10 */ 11 12#include <crypto/hash.h> 13#include <crypto/skcipher.h> 14#include <linux/err.h> 15#include <linux/module.h> 16#include <linux/init.h> 17#include <linux/types.h> 18#include <linux/slab.h> 19#include <linux/sunrpc/auth.h> 20#include <linux/sunrpc/gss_krb5.h> 21#include <linux/sunrpc/xdr.h> 22#include <linux/sunrpc/gss_krb5_enctypes.h> 23 24#include "auth_gss_internal.h" 25 26#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 27# define RPCDBG_FACILITY RPCDBG_AUTH 28#endif 29 30static struct gss_api_mech gss_kerberos_mech; /* forward declaration */ 31 32static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { 33#ifndef CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES 34 /* 35 * DES (All DES enctypes are mapped to the same gss functionality) 36 */ 37 { 38 .etype = ENCTYPE_DES_CBC_RAW, 39 .ctype = CKSUMTYPE_RSA_MD5, 40 .name = "des-cbc-crc", 41 .encrypt_name = "cbc(des)", 42 .cksum_name = "md5", 43 .encrypt = krb5_encrypt, 44 .decrypt = krb5_decrypt, 45 .mk_key = NULL, 46 .signalg = SGN_ALG_DES_MAC_MD5, 47 .sealalg = SEAL_ALG_DES, 48 .keybytes = 7, 49 .keylength = 8, 50 .blocksize = 8, 51 .conflen = 8, 52 .cksumlength = 8, 53 .keyed_cksum = 0, 54 }, 55#endif /* CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES */ 56 /* 57 * 3DES 58 */ 59 { 60 .etype = ENCTYPE_DES3_CBC_RAW, 61 .ctype = CKSUMTYPE_HMAC_SHA1_DES3, 62 .name = "des3-hmac-sha1", 63 .encrypt_name = "cbc(des3_ede)", 64 .cksum_name = "hmac(sha1)", 65 .encrypt = krb5_encrypt, 66 .decrypt = krb5_decrypt, 67 .mk_key = gss_krb5_des3_make_key, 68 .signalg = SGN_ALG_HMAC_SHA1_DES3_KD, 69 .sealalg = SEAL_ALG_DES3KD, 70 .keybytes = 21, 71 .keylength = 24, 72 .blocksize = 8, 73 .conflen = 8, 74 .cksumlength = 20, 75 .keyed_cksum = 1, 76 }, 77 /* 78 * AES128 79 */ 80 { 81 .etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96, 82 .ctype = CKSUMTYPE_HMAC_SHA1_96_AES128, 83 .name = "aes128-cts", 84 .encrypt_name = "cts(cbc(aes))", 85 .cksum_name = "hmac(sha1)", 86 .encrypt = krb5_encrypt, 87 .decrypt = krb5_decrypt, 88 .mk_key = gss_krb5_aes_make_key, 89 .encrypt_v2 = gss_krb5_aes_encrypt, 90 .decrypt_v2 = gss_krb5_aes_decrypt, 91 .signalg = -1, 92 .sealalg = -1, 93 .keybytes = 16, 94 .keylength = 16, 95 .blocksize = 16, 96 .conflen = 16, 97 .cksumlength = 12, 98 .keyed_cksum = 1, 99 }, 100 /* 101 * AES256 102 */ 103 { 104 .etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96, 105 .ctype = CKSUMTYPE_HMAC_SHA1_96_AES256, 106 .name = "aes256-cts", 107 .encrypt_name = "cts(cbc(aes))", 108 .cksum_name = "hmac(sha1)", 109 .encrypt = krb5_encrypt, 110 .decrypt = krb5_decrypt, 111 .mk_key = gss_krb5_aes_make_key, 112 .encrypt_v2 = gss_krb5_aes_encrypt, 113 .decrypt_v2 = gss_krb5_aes_decrypt, 114 .signalg = -1, 115 .sealalg = -1, 116 .keybytes = 32, 117 .keylength = 32, 118 .blocksize = 16, 119 .conflen = 16, 120 .cksumlength = 12, 121 .keyed_cksum = 1, 122 }, 123}; 124 125static const int num_supported_enctypes = 126 ARRAY_SIZE(supported_gss_krb5_enctypes); 127 128static int 129supported_gss_krb5_enctype(int etype) 130{ 131 int i; 132 for (i = 0; i < num_supported_enctypes; i++) 133 if (supported_gss_krb5_enctypes[i].etype == etype) 134 return 1; 135 return 0; 136} 137 138static const struct gss_krb5_enctype * 139get_gss_krb5_enctype(int etype) 140{ 141 int i; 142 for (i = 0; i < num_supported_enctypes; i++) 143 if (supported_gss_krb5_enctypes[i].etype == etype) 144 return &supported_gss_krb5_enctypes[i]; 145 return NULL; 146} 147 148static inline const void * 149get_key(const void *p, const void *end, 150 struct krb5_ctx *ctx, struct crypto_sync_skcipher **res) 151{ 152 struct xdr_netobj key; 153 int alg; 154 155 p = simple_get_bytes(p, end, &alg, sizeof(alg)); 156 if (IS_ERR(p)) 157 goto out_err; 158 159 switch (alg) { 160 case ENCTYPE_DES_CBC_CRC: 161 case ENCTYPE_DES_CBC_MD4: 162 case ENCTYPE_DES_CBC_MD5: 163 /* Map all these key types to ENCTYPE_DES_CBC_RAW */ 164 alg = ENCTYPE_DES_CBC_RAW; 165 break; 166 } 167 168 if (!supported_gss_krb5_enctype(alg)) { 169 printk(KERN_WARNING "gss_kerberos_mech: unsupported " 170 "encryption key algorithm %d\n", alg); 171 p = ERR_PTR(-EINVAL); 172 goto out_err; 173 } 174 p = simple_get_netobj(p, end, &key); 175 if (IS_ERR(p)) 176 goto out_err; 177 178 *res = crypto_alloc_sync_skcipher(ctx->gk5e->encrypt_name, 0, 0); 179 if (IS_ERR(*res)) { 180 printk(KERN_WARNING "gss_kerberos_mech: unable to initialize " 181 "crypto algorithm %s\n", ctx->gk5e->encrypt_name); 182 *res = NULL; 183 goto out_err_free_key; 184 } 185 if (crypto_sync_skcipher_setkey(*res, key.data, key.len)) { 186 printk(KERN_WARNING "gss_kerberos_mech: error setting key for " 187 "crypto algorithm %s\n", ctx->gk5e->encrypt_name); 188 goto out_err_free_tfm; 189 } 190 191 kfree(key.data); 192 return p; 193 194out_err_free_tfm: 195 crypto_free_sync_skcipher(*res); 196out_err_free_key: 197 kfree(key.data); 198 p = ERR_PTR(-EINVAL); 199out_err: 200 return p; 201} 202 203static int 204gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) 205{ 206 u32 seq_send; 207 int tmp; 208 u32 time32; 209 210 p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); 211 if (IS_ERR(p)) 212 goto out_err; 213 214 /* Old format supports only DES! Any other enctype uses new format */ 215 ctx->enctype = ENCTYPE_DES_CBC_RAW; 216 217 ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); 218 if (ctx->gk5e == NULL) { 219 p = ERR_PTR(-EINVAL); 220 goto out_err; 221 } 222 223 /* The downcall format was designed before we completely understood 224 * the uses of the context fields; so it includes some stuff we 225 * just give some minimal sanity-checking, and some we ignore 226 * completely (like the next twenty bytes): */ 227 if (unlikely(p + 20 > end || p + 20 < p)) { 228 p = ERR_PTR(-EFAULT); 229 goto out_err; 230 } 231 p += 20; 232 p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); 233 if (IS_ERR(p)) 234 goto out_err; 235 if (tmp != SGN_ALG_DES_MAC_MD5) { 236 p = ERR_PTR(-ENOSYS); 237 goto out_err; 238 } 239 p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); 240 if (IS_ERR(p)) 241 goto out_err; 242 if (tmp != SEAL_ALG_DES) { 243 p = ERR_PTR(-ENOSYS); 244 goto out_err; 245 } 246 p = simple_get_bytes(p, end, &time32, sizeof(time32)); 247 if (IS_ERR(p)) 248 goto out_err; 249 /* unsigned 32-bit time overflows in year 2106 */ 250 ctx->endtime = (time64_t)time32; 251 p = simple_get_bytes(p, end, &seq_send, sizeof(seq_send)); 252 if (IS_ERR(p)) 253 goto out_err; 254 atomic_set(&ctx->seq_send, seq_send); 255 p = simple_get_netobj(p, end, &ctx->mech_used); 256 if (IS_ERR(p)) 257 goto out_err; 258 p = get_key(p, end, ctx, &ctx->enc); 259 if (IS_ERR(p)) 260 goto out_err_free_mech; 261 p = get_key(p, end, ctx, &ctx->seq); 262 if (IS_ERR(p)) 263 goto out_err_free_key1; 264 if (p != end) { 265 p = ERR_PTR(-EFAULT); 266 goto out_err_free_key2; 267 } 268 269 return 0; 270 271out_err_free_key2: 272 crypto_free_sync_skcipher(ctx->seq); 273out_err_free_key1: 274 crypto_free_sync_skcipher(ctx->enc); 275out_err_free_mech: 276 kfree(ctx->mech_used.data); 277out_err: 278 return PTR_ERR(p); 279} 280 281static struct crypto_sync_skcipher * 282context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) 283{ 284 struct crypto_sync_skcipher *cp; 285 286 cp = crypto_alloc_sync_skcipher(cname, 0, 0); 287 if (IS_ERR(cp)) { 288 dprintk("gss_kerberos_mech: unable to initialize " 289 "crypto algorithm %s\n", cname); 290 return NULL; 291 } 292 if (crypto_sync_skcipher_setkey(cp, key, ctx->gk5e->keylength)) { 293 dprintk("gss_kerberos_mech: error setting key for " 294 "crypto algorithm %s\n", cname); 295 crypto_free_sync_skcipher(cp); 296 return NULL; 297 } 298 return cp; 299} 300 301static inline void 302set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed) 303{ 304 cdata[0] = (usage>>24)&0xff; 305 cdata[1] = (usage>>16)&0xff; 306 cdata[2] = (usage>>8)&0xff; 307 cdata[3] = usage&0xff; 308 cdata[4] = seed; 309} 310 311static int 312context_derive_keys_des3(struct krb5_ctx *ctx, gfp_t gfp_mask) 313{ 314 struct xdr_netobj c, keyin, keyout; 315 u8 cdata[GSS_KRB5_K5CLENGTH]; 316 u32 err; 317 318 c.len = GSS_KRB5_K5CLENGTH; 319 c.data = cdata; 320 321 keyin.data = ctx->Ksess; 322 keyin.len = ctx->gk5e->keylength; 323 keyout.len = ctx->gk5e->keylength; 324 325 /* seq uses the raw key */ 326 ctx->seq = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, 327 ctx->Ksess); 328 if (ctx->seq == NULL) 329 goto out_err; 330 331 ctx->enc = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, 332 ctx->Ksess); 333 if (ctx->enc == NULL) 334 goto out_free_seq; 335 336 /* derive cksum */ 337 set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM); 338 keyout.data = ctx->cksum; 339 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 340 if (err) { 341 dprintk("%s: Error %d deriving cksum key\n", 342 __func__, err); 343 goto out_free_enc; 344 } 345 346 return 0; 347 348out_free_enc: 349 crypto_free_sync_skcipher(ctx->enc); 350out_free_seq: 351 crypto_free_sync_skcipher(ctx->seq); 352out_err: 353 return -EINVAL; 354} 355 356static int 357context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask) 358{ 359 struct xdr_netobj c, keyin, keyout; 360 u8 cdata[GSS_KRB5_K5CLENGTH]; 361 u32 err; 362 363 c.len = GSS_KRB5_K5CLENGTH; 364 c.data = cdata; 365 366 keyin.data = ctx->Ksess; 367 keyin.len = ctx->gk5e->keylength; 368 keyout.len = ctx->gk5e->keylength; 369 370 /* initiator seal encryption */ 371 set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); 372 keyout.data = ctx->initiator_seal; 373 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 374 if (err) { 375 dprintk("%s: Error %d deriving initiator_seal key\n", 376 __func__, err); 377 goto out_err; 378 } 379 ctx->initiator_enc = context_v2_alloc_cipher(ctx, 380 ctx->gk5e->encrypt_name, 381 ctx->initiator_seal); 382 if (ctx->initiator_enc == NULL) 383 goto out_err; 384 385 /* acceptor seal encryption */ 386 set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); 387 keyout.data = ctx->acceptor_seal; 388 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 389 if (err) { 390 dprintk("%s: Error %d deriving acceptor_seal key\n", 391 __func__, err); 392 goto out_free_initiator_enc; 393 } 394 ctx->acceptor_enc = context_v2_alloc_cipher(ctx, 395 ctx->gk5e->encrypt_name, 396 ctx->acceptor_seal); 397 if (ctx->acceptor_enc == NULL) 398 goto out_free_initiator_enc; 399 400 /* initiator sign checksum */ 401 set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM); 402 keyout.data = ctx->initiator_sign; 403 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 404 if (err) { 405 dprintk("%s: Error %d deriving initiator_sign key\n", 406 __func__, err); 407 goto out_free_acceptor_enc; 408 } 409 410 /* acceptor sign checksum */ 411 set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM); 412 keyout.data = ctx->acceptor_sign; 413 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 414 if (err) { 415 dprintk("%s: Error %d deriving acceptor_sign key\n", 416 __func__, err); 417 goto out_free_acceptor_enc; 418 } 419 420 /* initiator seal integrity */ 421 set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY); 422 keyout.data = ctx->initiator_integ; 423 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 424 if (err) { 425 dprintk("%s: Error %d deriving initiator_integ key\n", 426 __func__, err); 427 goto out_free_acceptor_enc; 428 } 429 430 /* acceptor seal integrity */ 431 set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY); 432 keyout.data = ctx->acceptor_integ; 433 err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); 434 if (err) { 435 dprintk("%s: Error %d deriving acceptor_integ key\n", 436 __func__, err); 437 goto out_free_acceptor_enc; 438 } 439 440 switch (ctx->enctype) { 441 case ENCTYPE_AES128_CTS_HMAC_SHA1_96: 442 case ENCTYPE_AES256_CTS_HMAC_SHA1_96: 443 ctx->initiator_enc_aux = 444 context_v2_alloc_cipher(ctx, "cbc(aes)", 445 ctx->initiator_seal); 446 if (ctx->initiator_enc_aux == NULL) 447 goto out_free_acceptor_enc; 448 ctx->acceptor_enc_aux = 449 context_v2_alloc_cipher(ctx, "cbc(aes)", 450 ctx->acceptor_seal); 451 if (ctx->acceptor_enc_aux == NULL) { 452 crypto_free_sync_skcipher(ctx->initiator_enc_aux); 453 goto out_free_acceptor_enc; 454 } 455 } 456 457 return 0; 458 459out_free_acceptor_enc: 460 crypto_free_sync_skcipher(ctx->acceptor_enc); 461out_free_initiator_enc: 462 crypto_free_sync_skcipher(ctx->initiator_enc); 463out_err: 464 return -EINVAL; 465} 466 467static int 468gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, 469 gfp_t gfp_mask) 470{ 471 u64 seq_send64; 472 int keylen; 473 u32 time32; 474 475 p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); 476 if (IS_ERR(p)) 477 goto out_err; 478 ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR; 479 480 p = simple_get_bytes(p, end, &time32, sizeof(time32)); 481 if (IS_ERR(p)) 482 goto out_err; 483 /* unsigned 32-bit time overflows in year 2106 */ 484 ctx->endtime = (time64_t)time32; 485 p = simple_get_bytes(p, end, &seq_send64, sizeof(seq_send64)); 486 if (IS_ERR(p)) 487 goto out_err; 488 atomic64_set(&ctx->seq_send64, seq_send64); 489 /* set seq_send for use by "older" enctypes */ 490 atomic_set(&ctx->seq_send, seq_send64); 491 if (seq_send64 != atomic_read(&ctx->seq_send)) { 492 dprintk("%s: seq_send64 %llx, seq_send %x overflow?\n", __func__, 493 seq_send64, atomic_read(&ctx->seq_send)); 494 p = ERR_PTR(-EINVAL); 495 goto out_err; 496 } 497 p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); 498 if (IS_ERR(p)) 499 goto out_err; 500 /* Map ENCTYPE_DES3_CBC_SHA1 to ENCTYPE_DES3_CBC_RAW */ 501 if (ctx->enctype == ENCTYPE_DES3_CBC_SHA1) 502 ctx->enctype = ENCTYPE_DES3_CBC_RAW; 503 ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); 504 if (ctx->gk5e == NULL) { 505 dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n", 506 ctx->enctype); 507 p = ERR_PTR(-EINVAL); 508 goto out_err; 509 } 510 keylen = ctx->gk5e->keylength; 511 512 p = simple_get_bytes(p, end, ctx->Ksess, keylen); 513 if (IS_ERR(p)) 514 goto out_err; 515 516 if (p != end) { 517 p = ERR_PTR(-EINVAL); 518 goto out_err; 519 } 520 521 ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data, 522 gss_kerberos_mech.gm_oid.len, gfp_mask); 523 if (unlikely(ctx->mech_used.data == NULL)) { 524 p = ERR_PTR(-ENOMEM); 525 goto out_err; 526 } 527 ctx->mech_used.len = gss_kerberos_mech.gm_oid.len; 528 529 switch (ctx->enctype) { 530 case ENCTYPE_DES3_CBC_RAW: 531 return context_derive_keys_des3(ctx, gfp_mask); 532 case ENCTYPE_AES128_CTS_HMAC_SHA1_96: 533 case ENCTYPE_AES256_CTS_HMAC_SHA1_96: 534 return context_derive_keys_new(ctx, gfp_mask); 535 default: 536 return -EINVAL; 537 } 538 539out_err: 540 return PTR_ERR(p); 541} 542 543static int 544gss_import_sec_context_kerberos(const void *p, size_t len, 545 struct gss_ctx *ctx_id, 546 time64_t *endtime, 547 gfp_t gfp_mask) 548{ 549 const void *end = (const void *)((const char *)p + len); 550 struct krb5_ctx *ctx; 551 int ret; 552 553 ctx = kzalloc(sizeof(*ctx), gfp_mask); 554 if (ctx == NULL) 555 return -ENOMEM; 556 557 if (len == 85) 558 ret = gss_import_v1_context(p, end, ctx); 559 else 560 ret = gss_import_v2_context(p, end, ctx, gfp_mask); 561 562 if (ret == 0) { 563 ctx_id->internal_ctx_id = ctx; 564 if (endtime) 565 *endtime = ctx->endtime; 566 } else 567 kfree(ctx); 568 569 dprintk("RPC: %s: returning %d\n", __func__, ret); 570 return ret; 571} 572 573static void 574gss_delete_sec_context_kerberos(void *internal_ctx) { 575 struct krb5_ctx *kctx = internal_ctx; 576 577 crypto_free_sync_skcipher(kctx->seq); 578 crypto_free_sync_skcipher(kctx->enc); 579 crypto_free_sync_skcipher(kctx->acceptor_enc); 580 crypto_free_sync_skcipher(kctx->initiator_enc); 581 crypto_free_sync_skcipher(kctx->acceptor_enc_aux); 582 crypto_free_sync_skcipher(kctx->initiator_enc_aux); 583 kfree(kctx->mech_used.data); 584 kfree(kctx); 585} 586 587static const struct gss_api_ops gss_kerberos_ops = { 588 .gss_import_sec_context = gss_import_sec_context_kerberos, 589 .gss_get_mic = gss_get_mic_kerberos, 590 .gss_verify_mic = gss_verify_mic_kerberos, 591 .gss_wrap = gss_wrap_kerberos, 592 .gss_unwrap = gss_unwrap_kerberos, 593 .gss_delete_sec_context = gss_delete_sec_context_kerberos, 594}; 595 596static struct pf_desc gss_kerberos_pfs[] = { 597 [0] = { 598 .pseudoflavor = RPC_AUTH_GSS_KRB5, 599 .qop = GSS_C_QOP_DEFAULT, 600 .service = RPC_GSS_SVC_NONE, 601 .name = "krb5", 602 }, 603 [1] = { 604 .pseudoflavor = RPC_AUTH_GSS_KRB5I, 605 .qop = GSS_C_QOP_DEFAULT, 606 .service = RPC_GSS_SVC_INTEGRITY, 607 .name = "krb5i", 608 .datatouch = true, 609 }, 610 [2] = { 611 .pseudoflavor = RPC_AUTH_GSS_KRB5P, 612 .qop = GSS_C_QOP_DEFAULT, 613 .service = RPC_GSS_SVC_PRIVACY, 614 .name = "krb5p", 615 .datatouch = true, 616 }, 617}; 618 619MODULE_ALIAS("rpc-auth-gss-krb5"); 620MODULE_ALIAS("rpc-auth-gss-krb5i"); 621MODULE_ALIAS("rpc-auth-gss-krb5p"); 622MODULE_ALIAS("rpc-auth-gss-390003"); 623MODULE_ALIAS("rpc-auth-gss-390004"); 624MODULE_ALIAS("rpc-auth-gss-390005"); 625MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2"); 626 627static struct gss_api_mech gss_kerberos_mech = { 628 .gm_name = "krb5", 629 .gm_owner = THIS_MODULE, 630 .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }, 631 .gm_ops = &gss_kerberos_ops, 632 .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), 633 .gm_pfs = gss_kerberos_pfs, 634 .gm_upcall_enctypes = KRB5_SUPPORTED_ENCTYPES, 635}; 636 637static int __init init_kerberos_module(void) 638{ 639 int status; 640 641 status = gss_mech_register(&gss_kerberos_mech); 642 if (status) 643 printk("Failed to register kerberos gss mechanism!\n"); 644 return status; 645} 646 647static void __exit cleanup_kerberos_module(void) 648{ 649 gss_mech_unregister(&gss_kerberos_mech); 650} 651 652MODULE_LICENSE("GPL"); 653module_init(init_kerberos_module); 654module_exit(cleanup_kerberos_module);