1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * lib/krb5/krb/ser_actx.c 8 * 9 * Copyright 1995 by the Massachusetts Institute of Technology. 10 * All Rights Reserved. 11 * 12 * Export of this software from the United States of America may 13 * require a specific license from the United States Government. 14 * It is the responsibility of any person or organization contemplating 15 * export to obtain such a license before exporting. 16 * 17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 18 * distribute this software and its documentation for any purpose and 19 * without fee is hereby granted, provided that the above copyright 20 * notice appear in all copies and that both that copyright notice and 21 * this permission notice appear in supporting documentation, and that 22 * the name of M.I.T. not be used in advertising or publicity pertaining 23 * to distribution of the software without specific, written prior 24 * permission. Furthermore if you modify this software you must label 25 * your software as modified software and not distribute it in such a 26 * fashion that it might be confused with the original M.I.T. software. 27 * M.I.T. makes no representations about the suitability of 28 * this software for any purpose. It is provided "as is" without express 29 * or implied warranty. 30 * 31 */ 32 33 /* 34 * ser_actx.c - Serialize krb5_auth_context structure. 35 */ 36 #include "k5-int.h" 37 #include "int-proto.h" 38 #include "auth_con.h" 39 40 #define TOKEN_RADDR 950916 41 #define TOKEN_RPORT 950917 42 #define TOKEN_LADDR 950918 43 #define TOKEN_LPORT 950919 44 #define TOKEN_KEYBLOCK 950920 45 #define TOKEN_LSKBLOCK 950921 46 #define TOKEN_RSKBLOCK 950922 47 48 /* 49 * Routines to deal with externalizing the krb5_auth_context: 50 * krb5_auth_context_size(); 51 * krb5_auth_context_externalize(); 52 * krb5_auth_context_internalize(); 53 */ 54 static krb5_error_code krb5_auth_context_size 55 (krb5_context, krb5_pointer, size_t *); 56 static krb5_error_code krb5_auth_context_externalize 57 (krb5_context, krb5_pointer, krb5_octet **, size_t *); 58 static krb5_error_code krb5_auth_context_internalize 59 (krb5_context,krb5_pointer *, krb5_octet **, size_t *); 60 61 /* 62 * Other metadata serialization initializers. 63 */ 64 65 /* Local data */ 66 static const krb5_ser_entry krb5_auth_context_ser_entry = { 67 KV5M_AUTH_CONTEXT, /* Type */ 68 krb5_auth_context_size, /* Sizer routine */ 69 krb5_auth_context_externalize, /* Externalize routine */ 70 krb5_auth_context_internalize /* Internalize routine */ 71 }; 72 73 /* 74 * krb5_auth_context_size() - Determine the size required to externalize 75 * the krb5_auth_context. 76 */ 77 static krb5_error_code 78 krb5_auth_context_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep) 79 { 80 krb5_error_code kret; 81 krb5_auth_context auth_context; 82 size_t required; 83 84 /* 85 * krb5_auth_context requires at minimum: 86 * krb5_int32 for KV5M_AUTH_CONTEXT 87 * krb5_int32 for auth_context_flags 88 * krb5_int32 for remote_seq_number 89 * krb5_int32 for local_seq_number 90 * krb5_int32 for req_cksumtype 91 * krb5_int32 for safe_cksumtype 92 * krb5_int32 for size of i_vector 93 * krb5_int32 for KV5M_AUTH_CONTEXT 94 */ 95 kret = EINVAL; 96 /* Solaris Kerberos */ 97 auth_context = (krb5_auth_context) arg; 98 if (auth_context) { 99 kret = 0; 100 101 /* Calculate size required by i_vector - ptooey */ 102 if (auth_context->i_vector && auth_context->keyblock) { 103 kret = krb5_c_block_size(kcontext, auth_context->keyblock->enctype, 104 &required); 105 } else { 106 required = 0; 107 } 108 109 required += sizeof(krb5_int32)*8; 110 111 /* Calculate size required by remote_addr, if appropriate */ 112 if (!kret && auth_context->remote_addr) { 113 kret = krb5_size_opaque(kcontext, 114 KV5M_ADDRESS, 115 (krb5_pointer) auth_context->remote_addr, 116 &required); 117 if (!kret) 118 required += sizeof(krb5_int32); 119 } 120 121 /* Calculate size required by remote_port, if appropriate */ 122 if (!kret && auth_context->remote_port) { 123 kret = krb5_size_opaque(kcontext, 124 KV5M_ADDRESS, 125 (krb5_pointer) auth_context->remote_port, 126 &required); 127 if (!kret) 128 required += sizeof(krb5_int32); 129 } 130 131 /* Calculate size required by local_addr, if appropriate */ 132 if (!kret && auth_context->local_addr) { 133 kret = krb5_size_opaque(kcontext, 134 KV5M_ADDRESS, 135 (krb5_pointer) auth_context->local_addr, 136 &required); 137 if (!kret) 138 required += sizeof(krb5_int32); 139 } 140 141 /* Calculate size required by local_port, if appropriate */ 142 if (!kret && auth_context->local_port) { 143 kret = krb5_size_opaque(kcontext, 144 KV5M_ADDRESS, 145 (krb5_pointer) auth_context->local_port, 146 &required); 147 if (!kret) 148 required += sizeof(krb5_int32); 149 } 150 151 /* Calculate size required by keyblock, if appropriate */ 152 if (!kret && auth_context->keyblock) { 153 kret = krb5_size_opaque(kcontext, 154 KV5M_KEYBLOCK, 155 (krb5_pointer) auth_context->keyblock, 156 &required); 157 if (!kret) 158 required += sizeof(krb5_int32); 159 } 160 161 /* Calculate size required by send_subkey, if appropriate */ 162 if (!kret && auth_context->send_subkey) { 163 kret = krb5_size_opaque(kcontext, 164 KV5M_KEYBLOCK, 165 (krb5_pointer) auth_context->send_subkey, 166 &required); 167 if (!kret) 168 required += sizeof(krb5_int32); 169 } 170 171 /* Calculate size required by recv_subkey, if appropriate */ 172 if (!kret && auth_context->recv_subkey) { 173 kret = krb5_size_opaque(kcontext, 174 KV5M_KEYBLOCK, 175 (krb5_pointer) auth_context->recv_subkey, 176 &required); 177 if (!kret) 178 required += sizeof(krb5_int32); 179 } 180 181 /* Calculate size required by authentp, if appropriate */ 182 if (!kret && auth_context->authentp) 183 kret = krb5_size_opaque(kcontext, 184 KV5M_AUTHENTICATOR, 185 (krb5_pointer) auth_context->authentp, 186 &required); 187 188 } 189 if (!kret) 190 *sizep += required; 191 return(kret); 192 } 193 194 /* 195 * krb5_auth_context_externalize() - Externalize the krb5_auth_context. 196 */ 197 static krb5_error_code 198 krb5_auth_context_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain) 199 { 200 krb5_error_code kret; 201 krb5_auth_context auth_context; 202 size_t required; 203 krb5_octet *bp; 204 size_t remain; 205 size_t obuf; 206 krb5_int32 obuf32; 207 208 required = 0; 209 bp = *buffer; 210 remain = *lenremain; 211 kret = EINVAL; 212 /* Solaris Kerberos */ 213 auth_context = (krb5_auth_context) arg; 214 if (auth_context) { 215 kret = ENOMEM; 216 if (!krb5_auth_context_size(kcontext, arg, &required) && 217 (required <= remain)) { 218 219 /* Write fixed portion */ 220 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain); 221 (void) krb5_ser_pack_int32(auth_context->auth_context_flags, 222 &bp, &remain); 223 (void) krb5_ser_pack_int32(auth_context->remote_seq_number, 224 &bp, &remain); 225 (void) krb5_ser_pack_int32(auth_context->local_seq_number, 226 &bp, &remain); 227 (void) krb5_ser_pack_int32((krb5_int32) auth_context->req_cksumtype, 228 &bp, &remain); 229 (void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype, 230 &bp, &remain); 231 232 kret = 0; 233 234 /* Now figure out the number of bytes for i_vector and write it */ 235 if (auth_context->i_vector) { 236 kret = krb5_c_block_size(kcontext, 237 auth_context->keyblock->enctype, 238 &obuf); 239 } else { 240 obuf = 0; 241 } 242 243 /* Convert to signed 32 bit integer */ 244 obuf32 = obuf; 245 if (kret == 0 && obuf != obuf32) 246 kret = EINVAL; 247 if (!kret) 248 (void) krb5_ser_pack_int32(obuf32, &bp, &remain); 249 250 /* Now copy i_vector */ 251 if (!kret && auth_context->i_vector) 252 (void) krb5_ser_pack_bytes(auth_context->i_vector, 253 obuf, 254 &bp, &remain); 255 256 /* Now handle remote_addr, if appropriate */ 257 if (!kret && auth_context->remote_addr) { 258 (void) krb5_ser_pack_int32(TOKEN_RADDR, &bp, &remain); 259 kret = krb5_externalize_opaque(kcontext, 260 KV5M_ADDRESS, 261 (krb5_pointer) 262 auth_context->remote_addr, 263 &bp, 264 &remain); 265 } 266 267 /* Now handle remote_port, if appropriate */ 268 if (!kret && auth_context->remote_port) { 269 (void) krb5_ser_pack_int32(TOKEN_RPORT, &bp, &remain); 270 kret = krb5_externalize_opaque(kcontext, 271 KV5M_ADDRESS, 272 (krb5_pointer) 273 auth_context->remote_addr, 274 &bp, 275 &remain); 276 } 277 278 /* Now handle local_addr, if appropriate */ 279 if (!kret && auth_context->local_addr) { 280 (void) krb5_ser_pack_int32(TOKEN_LADDR, &bp, &remain); 281 kret = krb5_externalize_opaque(kcontext, 282 KV5M_ADDRESS, 283 (krb5_pointer) 284 auth_context->local_addr, 285 &bp, 286 &remain); 287 } 288 289 /* Now handle local_port, if appropriate */ 290 if (!kret && auth_context->local_port) { 291 (void) krb5_ser_pack_int32(TOKEN_LPORT, &bp, &remain); 292 kret = krb5_externalize_opaque(kcontext, 293 KV5M_ADDRESS, 294 (krb5_pointer) 295 auth_context->local_addr, 296 &bp, 297 &remain); 298 } 299 300 /* Now handle keyblock, if appropriate */ 301 if (!kret && auth_context->keyblock) { 302 (void) krb5_ser_pack_int32(TOKEN_KEYBLOCK, &bp, &remain); 303 kret = krb5_externalize_opaque(kcontext, 304 KV5M_KEYBLOCK, 305 (krb5_pointer) 306 auth_context->keyblock, 307 &bp, 308 &remain); 309 } 310 311 /* Now handle subkey, if appropriate */ 312 if (!kret && auth_context->send_subkey) { 313 (void) krb5_ser_pack_int32(TOKEN_LSKBLOCK, &bp, &remain); 314 kret = krb5_externalize_opaque(kcontext, 315 KV5M_KEYBLOCK, 316 (krb5_pointer) 317 auth_context->send_subkey, 318 &bp, 319 &remain); 320 } 321 322 /* Now handle subkey, if appropriate */ 323 if (!kret && auth_context->recv_subkey) { 324 (void) krb5_ser_pack_int32(TOKEN_RSKBLOCK, &bp, &remain); 325 kret = krb5_externalize_opaque(kcontext, 326 KV5M_KEYBLOCK, 327 (krb5_pointer) 328 auth_context->recv_subkey, 329 &bp, 330 &remain); 331 } 332 333 /* Now handle authentp, if appropriate */ 334 if (!kret && auth_context->authentp) 335 kret = krb5_externalize_opaque(kcontext, 336 KV5M_AUTHENTICATOR, 337 (krb5_pointer) 338 auth_context->authentp, 339 &bp, 340 &remain); 341 342 /* 343 * If we were successful, write trailer then update the pointer and 344 * remaining length; 345 */ 346 if (!kret) { 347 /* Write our trailer */ 348 (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain); 349 *buffer = bp; 350 *lenremain = remain; 351 } 352 } 353 } 354 return(kret); 355 } 356 357 /* 358 * krb5_auth_context_internalize() - Internalize the krb5_auth_context. 359 */ 360 static krb5_error_code 361 krb5_auth_context_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain) 362 { 363 krb5_error_code kret; 364 krb5_auth_context auth_context; 365 krb5_int32 ibuf; 366 krb5_octet *bp; 367 size_t remain; 368 krb5_int32 ivlen; 369 krb5_int32 tag; 370 371 bp = *buffer; 372 remain = *lenremain; 373 kret = EINVAL; 374 /* Read our magic number */ 375 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) 376 ibuf = 0; 377 if (ibuf == KV5M_AUTH_CONTEXT) { 378 kret = ENOMEM; 379 380 /* Get memory for the auth_context */ 381 if ((remain >= (5*sizeof(krb5_int32))) && 382 (auth_context = (krb5_auth_context) 383 MALLOC(sizeof(struct _krb5_auth_context)))) { 384 (void) memset(auth_context, 0, sizeof(struct _krb5_auth_context)); 385 386 /* Get auth_context_flags */ 387 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 388 auth_context->auth_context_flags = ibuf; 389 390 /* Get remote_seq_number */ 391 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 392 auth_context->remote_seq_number = ibuf; 393 394 /* Get local_seq_number */ 395 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 396 auth_context->local_seq_number = ibuf; 397 398 /* Get req_cksumtype */ 399 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 400 auth_context->req_cksumtype = (krb5_cksumtype) ibuf; 401 402 /* Get safe_cksumtype */ 403 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 404 auth_context->safe_cksumtype = (krb5_cksumtype) ibuf; 405 406 /* Get length of i_vector */ 407 (void) krb5_ser_unpack_int32(&ivlen, &bp, &remain); 408 409 if (ivlen) { 410 if ((auth_context->i_vector = 411 (krb5_pointer) MALLOC((size_t)ivlen))) 412 kret = krb5_ser_unpack_bytes(auth_context->i_vector, 413 (size_t) ivlen, 414 &bp, 415 &remain); 416 else 417 kret = ENOMEM; 418 } 419 else 420 kret = 0; 421 422 /* Peek at next token */ 423 tag = 0; 424 if (!kret) 425 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 426 427 /* This is the remote_addr */ 428 if (!kret && (tag == TOKEN_RADDR)) { 429 if (!(kret = krb5_internalize_opaque(kcontext, 430 KV5M_ADDRESS, 431 (krb5_pointer *) 432 &auth_context-> 433 remote_addr, 434 &bp, 435 &remain))) 436 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 437 } 438 439 /* This is the remote_port */ 440 if (!kret && (tag == TOKEN_RPORT)) { 441 if (!(kret = krb5_internalize_opaque(kcontext, 442 KV5M_ADDRESS, 443 (krb5_pointer *) 444 &auth_context-> 445 remote_port, 446 &bp, 447 &remain))) 448 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 449 } 450 451 /* This is the local_addr */ 452 if (!kret && (tag == TOKEN_LADDR)) { 453 if (!(kret = krb5_internalize_opaque(kcontext, 454 KV5M_ADDRESS, 455 (krb5_pointer *) 456 &auth_context-> 457 local_addr, 458 &bp, 459 &remain))) 460 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 461 } 462 463 /* This is the local_port */ 464 if (!kret && (tag == TOKEN_LPORT)) { 465 if (!(kret = krb5_internalize_opaque(kcontext, 466 KV5M_ADDRESS, 467 (krb5_pointer *) 468 &auth_context-> 469 local_port, 470 &bp, 471 &remain))) 472 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 473 } 474 475 /* This is the keyblock */ 476 if (!kret && (tag == TOKEN_KEYBLOCK)) { 477 if (!(kret = krb5_internalize_opaque(kcontext, 478 KV5M_KEYBLOCK, 479 (krb5_pointer *) 480 &auth_context->keyblock, 481 &bp, 482 &remain))) 483 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 484 } 485 486 /* This is the send_subkey */ 487 if (!kret && (tag == TOKEN_LSKBLOCK)) { 488 if (!(kret = krb5_internalize_opaque(kcontext, 489 KV5M_KEYBLOCK, 490 (krb5_pointer *) 491 &auth_context-> 492 send_subkey, 493 &bp, 494 &remain))) 495 kret = krb5_ser_unpack_int32(&tag, &bp, &remain); 496 } 497 498 /* This is the recv_subkey */ 499 if (!kret) { 500 if (tag == TOKEN_RSKBLOCK) { 501 kret = krb5_internalize_opaque(kcontext, 502 KV5M_KEYBLOCK, 503 (krb5_pointer *) 504 &auth_context-> 505 recv_subkey, 506 &bp, 507 &remain); 508 } 509 else { 510 /* 511 * We read the next tag, but it's not of any use here, so 512 * we effectively 'unget' it here. 513 */ 514 bp -= sizeof(krb5_int32); 515 remain += sizeof(krb5_int32); 516 } 517 } 518 519 /* Now find the authentp */ 520 if (!kret) { 521 if ((kret = krb5_internalize_opaque(kcontext, 522 KV5M_AUTHENTICATOR, 523 (krb5_pointer *) 524 &auth_context->authentp, 525 &bp, 526 &remain))) { 527 if (kret == EINVAL) 528 kret = 0; 529 } 530 } 531 532 /* Finally, find the trailer */ 533 if (!kret) { 534 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); 535 if (!kret && (ibuf != KV5M_AUTH_CONTEXT)) 536 kret = EINVAL; 537 } 538 if (!kret) { 539 *buffer = bp; 540 *lenremain = remain; 541 auth_context->magic = KV5M_AUTH_CONTEXT; 542 *argp = (krb5_pointer) auth_context; 543 } 544 /* We don't import the auth_context into the kernel */ 545 #ifndef _KERNEL 546 else 547 krb5_auth_con_free(kcontext, auth_context); 548 #endif 549 } 550 } 551 return(kret); 552 } 553 554 /* 555 * Register the auth_context serializer. 556 */ 557 krb5_error_code KRB5_CALLCONV 558 krb5_ser_auth_context_init(krb5_context kcontext) 559 { 560 krb5_error_code kret; 561 kret = krb5_register_serializer(kcontext, &krb5_auth_context_ser_entry); 562 if (!kret) 563 kret = krb5_ser_authdata_init(kcontext); 564 if (!kret) 565 kret = krb5_ser_address_init(kcontext); 566 if (!kret) 567 kret = krb5_ser_authenticator_init(kcontext); 568 if (!kret) 569 kret = krb5_ser_checksum_init(kcontext); 570 if (!kret) 571 kret = krb5_ser_keyblock_init(kcontext); 572 if (!kret) 573 kret = krb5_ser_principal_init(kcontext); 574 return(kret); 575 } 576