1 /* 2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Copyright (c) 1983 Regents of the University of California. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms are permitted 13 * provided that the above copyright notice and this paragraph are 14 * duplicated in all such forms and that any documentation, 15 * advertising materials, and other materials related to such 16 * distribution and use acknowledge that the software was developed 17 * by the University of California, Berkeley. The name of the 18 * University may not be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 22 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 23 */ 24 25 /* derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88 */ 26 27 #include <unistd.h> 28 #include <stdlib.h> 29 #include <stdio.h> 30 #include <ctype.h> 31 #include <string.h> 32 #include <pwd.h> 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <fcntl.h> 36 37 #include <signal.h> 38 #include <sys/file.h> 39 #include <sys/socket.h> 40 #include <sys/stat.h> 41 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 #include <netdb.h> 45 #include <locale.h> 46 #include <syslog.h> 47 48 #include <errno.h> 49 #include <com_err.h> 50 #include <k5-int.h> 51 #include <kcmd.h> 52 53 static char *default_service = "host"; 54 55 #define KCMD_BUFSIZ 102400 56 #define KCMD_KEYUSAGE 1026 57 58 static char storage[KCMD_BUFSIZ]; 59 static int nstored = 0; 60 static int MAXSIZE = (KCMD_BUFSIZ + 8); 61 static char *store_ptr = storage; 62 static krb5_data desinbuf, desoutbuf; 63 64 static boolean_t encrypt_flag = B_FALSE; 65 static krb5_context kcmd_context; 66 67 /* XXX Overloaded: use_ivecs!=0 -> new protocol, inband signalling, etc. */ 68 static boolean_t use_ivecs = B_FALSE; 69 static krb5_data encivec_i[2], encivec_o[2]; 70 static krb5_keyusage enc_keyusage_i[2], enc_keyusage_o[2]; 71 static krb5_enctype final_enctype; 72 static krb5_keyblock *skey; 73 74 /* ARGSUSED */ 75 int 76 kcmd(int *sock, char **ahost, ushort_t rport, 77 char *locuser, char *remuser, 78 char *cmd, int *fd2p, char *service, char *realm, 79 krb5_context bsd_context, krb5_auth_context *authconp, 80 krb5_creds **cred, krb5_int32 *seqno, krb5_int32 *server_seqno, 81 krb5_flags authopts, 82 int anyport, enum kcmd_proto *protonump) 83 { 84 int s = -1; 85 sigset_t oldmask, urgmask; 86 struct sockaddr_in sin; 87 struct sockaddr_storage from; 88 krb5_creds *get_cred = NULL; 89 krb5_creds *ret_cred = NULL; 90 char c; 91 struct hostent *hp; 92 int rc; 93 char *host_save = NULL; 94 krb5_error_code status; 95 krb5_ap_rep_enc_part *rep_ret; 96 krb5_error *error = 0; 97 krb5_ccache cc; 98 krb5_data outbuf; 99 krb5_flags options = authopts; 100 krb5_auth_context auth_context = NULL; 101 char *cksumbuf; 102 krb5_data cksumdat; 103 int bsize = 0; 104 char *kcmd_version; 105 enum kcmd_proto protonum = *protonump; 106 107 bsize = strlen(cmd) + strlen(remuser) + 64; 108 if ((cksumbuf = malloc(bsize)) == 0) { 109 (void) fprintf(stderr, gettext("Unable to allocate" 110 " memory for checksum buffer.\n")); 111 return (-1); 112 } 113 (void) snprintf(cksumbuf, bsize, "%u:", ntohs(rport)); 114 if (strlcat(cksumbuf, cmd, bsize) >= bsize) { 115 (void) fprintf(stderr, gettext("cmd buffer too long.\n")); 116 free(cksumbuf); 117 return (-1); 118 } 119 if (strlcat(cksumbuf, remuser, bsize) >= bsize) { 120 (void) fprintf(stderr, gettext("remuser too long.\n")); 121 free(cksumbuf); 122 return (-1); 123 } 124 cksumdat.data = cksumbuf; 125 cksumdat.length = strlen(cksumbuf); 126 127 hp = gethostbyname(*ahost); 128 if (hp == 0) { 129 (void) fprintf(stderr, 130 gettext("%s: unknown host\n"), *ahost); 131 return (-1); 132 } 133 134 if ((host_save = (char *)strdup(hp->h_name)) == NULL) { 135 (void) fprintf(stderr, gettext("kcmd: no memory\n")); 136 return (-1); 137 } 138 139 /* If no service is given set to the default service */ 140 if (!service) service = default_service; 141 142 if (!(get_cred = (krb5_creds *)calloc(1, sizeof (krb5_creds)))) { 143 (void) fprintf(stderr, gettext("kcmd: no memory\n")); 144 return (-1); 145 } 146 (void) sigemptyset(&urgmask); 147 (void) sigaddset(&urgmask, SIGURG); 148 (void) sigprocmask(SIG_BLOCK, &urgmask, &oldmask); 149 150 status = krb5_sname_to_principal(bsd_context, host_save, service, 151 KRB5_NT_SRV_HST, &get_cred->server); 152 if (status) { 153 (void) fprintf(stderr, 154 gettext("kcmd: " 155 "krb5_sname_to_principal failed: %s\n"), 156 error_message(status)); 157 status = -1; 158 goto bad; 159 } 160 161 if (realm && *realm) { 162 (void) krb5_xfree( 163 krb5_princ_realm(bsd_context, get_cred->server)->data); 164 krb5_princ_set_realm_length(bsd_context, get_cred->server, 165 strlen(realm)); 166 krb5_princ_set_realm_data(bsd_context, get_cred->server, 167 strdup(realm)); 168 } 169 170 s = socket(AF_INET, SOCK_STREAM, 0); 171 if (s < 0) { 172 perror(gettext("Error creating socket")); 173 status = -1; 174 goto bad; 175 } 176 /* 177 * Kerberos only supports IPv4 addresses for now. 178 */ 179 if (hp->h_addrtype == AF_INET) { 180 sin.sin_family = hp->h_addrtype; 181 (void) memcpy((void *)&sin.sin_addr, 182 hp->h_addr, hp->h_length); 183 sin.sin_port = rport; 184 } else { 185 syslog(LOG_ERR, "Address type %d not supported for " 186 "Kerberos", hp->h_addrtype); 187 status = -1; 188 goto bad; 189 } 190 191 if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 192 perror(host_save); 193 status = -1; 194 goto bad; 195 } 196 197 if (fd2p == 0) { 198 (void) write(s, "", 1); 199 } else { 200 char num[16]; 201 int s2; 202 int s3; 203 struct sockaddr_storage sname; 204 struct sockaddr_in *sp; 205 int len = sizeof (struct sockaddr_storage); 206 207 s2 = socket(AF_INET, SOCK_STREAM, 0); 208 if (s2 < 0) { 209 status = -1; 210 goto bad; 211 } 212 (void) memset((char *)&sin, 0, sizeof (sin)); 213 sin.sin_family = AF_INET; 214 sin.sin_addr.s_addr = INADDR_ANY; 215 sin.sin_port = 0; 216 217 if (bind(s2, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 218 perror(gettext("error binding socket")); 219 (void) close(s2); 220 status = -1; 221 goto bad; 222 } 223 if (getsockname(s2, (struct sockaddr *)&sname, &len) < 0) { 224 perror(gettext("getsockname error")); 225 (void) close(s2); 226 status = -1; 227 goto bad; 228 } 229 sp = (struct sockaddr_in *)&sname; 230 (void) listen(s2, 1); 231 (void) snprintf(num, sizeof (num), "%d", 232 htons((ushort_t)sp->sin_port)); 233 if (write(s, num, strlen(num)+1) != strlen(num)+1) { 234 perror(gettext("write: error setting up stderr")); 235 (void) close(s2); 236 status = -1; 237 goto bad; 238 } 239 240 s3 = accept(s2, (struct sockaddr *)&from, &len); 241 (void) close(s2); 242 if (s3 < 0) { 243 perror(gettext("accept")); 244 status = -1; 245 goto bad; 246 } 247 *fd2p = s3; 248 if (SOCK_FAMILY(from) == AF_INET) { 249 if (!anyport && SOCK_PORT(from) >= IPPORT_RESERVED) { 250 (void) fprintf(stderr, 251 gettext("socket: protocol " 252 "failure in circuit setup.\n")); 253 status = -1; 254 goto bad2; 255 } 256 } else { 257 (void) fprintf(stderr, 258 gettext("Kerberos does not support " 259 "address type %d\n"), 260 SOCK_FAMILY(from)); 261 status = -1; 262 goto bad2; 263 } 264 } 265 266 if (status = krb5_cc_default(bsd_context, &cc)) 267 goto bad2; 268 269 status = krb5_cc_get_principal(bsd_context, cc, &get_cred->client); 270 if (status) { 271 (void) krb5_cc_close(bsd_context, cc); 272 goto bad2; 273 } 274 275 /* Get ticket from credentials cache or kdc */ 276 status = krb5_get_credentials(bsd_context, 0, cc, get_cred, &ret_cred); 277 (void) krb5_cc_close(bsd_context, cc); 278 if (status) goto bad2; 279 280 /* Reset internal flags; these should not be sent. */ 281 authopts &= (~OPTS_FORWARD_CREDS); 282 authopts &= (~OPTS_FORWARDABLE_CREDS); 283 284 if ((status = krb5_auth_con_init(bsd_context, &auth_context))) 285 goto bad2; 286 287 if ((status = krb5_auth_con_setflags(bsd_context, auth_context, 288 KRB5_AUTH_CONTEXT_RET_TIME))) 289 goto bad2; 290 291 /* Only need local address for mk_cred() to send to krlogind */ 292 if ((status = krb5_auth_con_genaddrs(bsd_context, auth_context, s, 293 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) 294 goto bad2; 295 296 if (protonum == KCMD_PROTOCOL_COMPAT_HACK) { 297 krb5_boolean is_des; 298 status = krb5_c_enctype_compare(bsd_context, 299 ENCTYPE_DES_CBC_CRC, 300 ret_cred->keyblock.enctype, 301 &is_des); 302 if (status) 303 goto bad2; 304 protonum = is_des ? KCMD_OLD_PROTOCOL : KCMD_NEW_PROTOCOL; 305 } 306 307 switch (protonum) { 308 case KCMD_NEW_PROTOCOL: 309 authopts |= AP_OPTS_USE_SUBKEY; 310 kcmd_version = "KCMDV0.2"; 311 break; 312 case KCMD_OLD_PROTOCOL: 313 kcmd_version = "KCMDV0.1"; 314 break; 315 default: 316 status = -1; 317 goto bad2; 318 } 319 320 /* 321 * Call the Kerberos library routine to obtain an authenticator, 322 * pass it over the socket to the server, and obtain mutual 323 * authentication. 324 */ 325 status = krb5_sendauth(bsd_context, &auth_context, (krb5_pointer) &s, 326 kcmd_version, ret_cred->client, ret_cred->server, 327 authopts, &cksumdat, ret_cred, 0, &error, 328 &rep_ret, NULL); 329 krb5_xfree(cksumdat.data); 330 if (status) { 331 (void) fprintf(stderr, gettext("Couldn't authenticate" 332 " to server: %s\n"), 333 error_message(status)); 334 if (error) { 335 (void) fprintf(stderr, gettext("Server returned error" 336 " code %d (%s)\n"), 337 error->error, 338 error_message(ERROR_TABLE_BASE_krb5 + 339 error->error)); 340 if (error->text.length) 341 (void) fprintf(stderr, 342 gettext("Error text" 343 " sent from server: %s\n"), 344 error->text.data); 345 } 346 if (error) { 347 krb5_free_error(bsd_context, error); 348 error = 0; 349 } 350 goto bad2; 351 } 352 if (rep_ret && server_seqno) { 353 *server_seqno = rep_ret->seq_number; 354 krb5_free_ap_rep_enc_part(bsd_context, rep_ret); 355 } 356 357 (void) write(s, remuser, strlen(remuser)+1); 358 (void) write(s, cmd, strlen(cmd)+1); 359 if (locuser) 360 (void) write(s, locuser, strlen(locuser)+1); 361 else 362 (void) write(s, "", 1); 363 364 if (options & OPTS_FORWARD_CREDS) { /* Forward credentials */ 365 if (status = krb5_fwd_tgt_creds(bsd_context, auth_context, 366 host_save, 367 ret_cred->client, ret_cred->server, 368 0, options & OPTS_FORWARDABLE_CREDS, 369 &outbuf)) { 370 (void) fprintf(stderr, 371 gettext("kcmd: Error getting" 372 " forwarded creds\n")); 373 goto bad2; 374 } 375 /* Send forwarded credentials */ 376 if (status = krb5_write_message(bsd_context, (krb5_pointer)&s, 377 &outbuf)) 378 goto bad2; 379 } else { /* Dummy write to signal no forwarding */ 380 outbuf.length = 0; 381 if (status = krb5_write_message(bsd_context, 382 (krb5_pointer)&s, &outbuf)) 383 goto bad2; 384 } 385 386 if ((rc = read(s, &c, 1)) != 1) { 387 if (rc == -1) { 388 perror(*ahost); 389 } else { 390 (void) fprintf(stderr, gettext("kcmd: bad connection " 391 "with remote host\n")); 392 } 393 status = -1; 394 goto bad2; 395 } 396 if (c != 0) { 397 while (read(s, &c, 1) == 1) { 398 (void) write(2, &c, 1); 399 if (c == '\n') 400 break; 401 } 402 status = -1; 403 goto bad2; 404 } 405 (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); 406 *sock = s; 407 408 /* pass back credentials if wanted */ 409 if (cred) krb5_copy_creds(bsd_context, ret_cred, cred); 410 krb5_free_creds(bsd_context, ret_cred); 411 /* 412 * Initialize *authconp to auth_context, so 413 * that the clients can make use of it 414 */ 415 *authconp = auth_context; 416 417 return (0); 418 bad2: 419 if (fd2p != NULL) 420 (void) close(*fd2p); 421 bad: 422 if (s > 0) 423 (void) close(s); 424 if (get_cred) 425 krb5_free_creds(bsd_context, get_cred); 426 if (ret_cred) 427 krb5_free_creds(bsd_context, ret_cred); 428 if (host_save) 429 free(host_save); 430 (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); 431 return (status); 432 } 433 434 /* 435 * Strsave was a routine in the version 4 krb library: we put it here 436 * for compatablilty with version 5 krb library, since kcmd.o is linked 437 * into all programs. 438 */ 439 440 char * 441 strsave(char *sp) 442 { 443 char *ret; 444 445 if ((ret = (char *)strdup(sp)) == NULL) { 446 (void) fprintf(stderr, gettext("no memory for saving args\n")); 447 exit(1); 448 } 449 return (ret); 450 } 451 452 /* 453 * Decode, decrypt and store the forwarded creds in the local ccache. 454 */ 455 krb5_error_code 456 rd_and_store_for_creds(krb5_context context, 457 krb5_auth_context auth_context, 458 krb5_data *inbuf, 459 krb5_ticket *ticket, 460 char *lusername, 461 krb5_ccache *ccache) 462 { 463 krb5_creds ** creds; 464 krb5_error_code retval; 465 char ccname[64]; 466 struct passwd *pwd; 467 uid_t uid; 468 469 *ccache = NULL; 470 if (!(pwd = (struct passwd *)getpwnam(lusername))) 471 return (ENOENT); 472 473 uid = getuid(); 474 if (seteuid(pwd->pw_uid)) 475 return (-1); 476 477 if ((retval = 478 krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) != 0) 479 return (retval); 480 481 (void) snprintf(ccname, sizeof (ccname), 482 "FILE:/tmp/krb5cc_%ld", pwd->pw_uid); 483 484 if ((retval = krb5_cc_resolve(context, ccname, ccache)) != 0) 485 goto cleanup; 486 487 if ((retval = krb5_cc_initialize(context, *ccache, 488 ticket->enc_part2->client)) != 0) 489 goto cleanup; 490 491 if ((retval = krb5_cc_store_cred(context, *ccache, *creds)) != 0) 492 goto cleanup; 493 494 if ((retval = krb5_cc_close(context, *ccache)) != 0) 495 goto cleanup; 496 497 cleanup: 498 (void) seteuid(uid); 499 krb5_free_creds(context, *creds); 500 return (retval); 501 } 502 503 /* 504 * This routine is to initialize the desinbuf, desoutbuf and the session key 505 * structures to carry out desread()'s and deswrite()'s successfully 506 */ 507 void 508 init_encrypt(int enc, krb5_context ctxt, enum kcmd_proto protonum, 509 krb5_data *inbuf, krb5_data *outbuf, 510 int amclient, krb5_encrypt_block *block) 511 { 512 krb5_error_code statuscode; 513 size_t blocksize; 514 int i; 515 krb5_error_code ret; 516 517 kcmd_context = ctxt; 518 519 if (enc > 0) { 520 desinbuf.data = inbuf->data; 521 desoutbuf.data = outbuf->data + 4; 522 desinbuf.length = inbuf->length; 523 desoutbuf.length = outbuf->length + 4; 524 encrypt_flag = B_TRUE; 525 } else { 526 encrypt_flag = B_FALSE; 527 return; 528 } 529 530 skey = block->key; 531 final_enctype = skey->enctype; 532 533 enc_keyusage_i[0] = KCMD_KEYUSAGE; 534 enc_keyusage_i[1] = KCMD_KEYUSAGE; 535 enc_keyusage_o[0] = KCMD_KEYUSAGE; 536 enc_keyusage_o[1] = KCMD_KEYUSAGE; 537 538 if (protonum == KCMD_OLD_PROTOCOL) { 539 use_ivecs = B_FALSE; 540 return; 541 } 542 543 use_ivecs = B_TRUE; 544 switch (skey->enctype) { 545 /* 546 * For the DES-based enctypes and the 3DES enctype we 547 * want to use a non-zero IV because that's what we did. 548 * In the future we use different keyusage for each 549 * channel and direction and a fresh cipher state. 550 */ 551 case ENCTYPE_DES_CBC_CRC: 552 case ENCTYPE_DES_CBC_MD4: 553 case ENCTYPE_DES_CBC_MD5: 554 case ENCTYPE_DES3_CBC_SHA1: 555 statuscode = krb5_c_block_size(kcmd_context, final_enctype, 556 &blocksize); 557 if (statuscode) { 558 /* XXX what do I do? */ 559 abort(); 560 } 561 562 encivec_i[0].length = encivec_i[1].length = 563 encivec_o[0].length = encivec_o[1].length = blocksize; 564 565 if ((encivec_i[0].data = malloc(encivec_i[0].length * 4)) 566 == NULL) { 567 /* XXX what do I do? */ 568 abort(); 569 } 570 encivec_i[1].data = encivec_i[0].data + encivec_i[0].length; 571 encivec_o[0].data = encivec_i[1].data + encivec_i[0].length; 572 encivec_o[1].data = encivec_o[0].data + encivec_i[0].length; 573 574 /* is there a better way to initialize this? */ 575 (void) memset(encivec_i[0].data, amclient, blocksize); 576 (void) memset(encivec_o[0].data, 1 - amclient, blocksize); 577 (void) memset(encivec_i[1].data, 2 | amclient, blocksize); 578 (void) memset(encivec_o[1].data, 2 | (1 - amclient), blocksize); 579 break; 580 default: 581 if (amclient) { 582 enc_keyusage_i[0] = 1028; 583 enc_keyusage_i[1] = 1030; 584 enc_keyusage_o[0] = 1032; 585 enc_keyusage_o[1] = 1034; 586 } else { /* amclient */ 587 enc_keyusage_i[0] = 1032; 588 enc_keyusage_i[1] = 1034; 589 enc_keyusage_o[0] = 1028; 590 enc_keyusage_o[1] = 1030; 591 } 592 for (i = 0; i < 2; i++) { 593 ret = krb5_c_init_state(ctxt, 594 skey, enc_keyusage_i[i], 595 &encivec_i[i]); 596 if (ret) 597 goto fail; 598 ret = krb5_c_init_state(ctxt, 599 skey, enc_keyusage_o[i], 600 &encivec_o[i]); 601 if (ret) 602 goto fail; 603 } 604 break; 605 } 606 return; 607 fail: 608 abort(); 609 } 610 611 int 612 desread(int fd, char *buf, int len, int secondary) 613 { 614 int nreturned = 0; 615 long net_len, rd_len; 616 int cc; 617 size_t ret = 0; 618 unsigned char len_buf[4]; 619 krb5_enc_data inputd; 620 krb5_data outputd; 621 622 if (!encrypt_flag) 623 return (read(fd, buf, len)); 624 625 /* 626 * If there is stored data from a previous read, 627 * put it into the output buffer and return it now. 628 */ 629 if (nstored >= len) { 630 (void) memcpy(buf, store_ptr, len); 631 store_ptr += len; 632 nstored -= len; 633 return (len); 634 } else if (nstored) { 635 (void) memcpy(buf, store_ptr, nstored); 636 nreturned += nstored; 637 buf += nstored; 638 len -= nstored; 639 nstored = 0; 640 } 641 642 if ((cc = krb5_net_read(kcmd_context, fd, (char *)len_buf, 4)) != 4) { 643 if ((cc < 0) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) 644 return (cc); 645 /* XXX can't read enough, pipe must have closed */ 646 return (0); 647 } 648 rd_len = ((len_buf[0] << 24) | (len_buf[1] << 16) | 649 (len_buf[2] << 8) | len_buf[3]); 650 651 if (krb5_c_encrypt_length(kcmd_context, final_enctype, 652 use_ivecs ? (size_t)rd_len + 4 : (size_t)rd_len, 653 &ret)) 654 net_len = ((size_t)-1); 655 else 656 net_len = ret; 657 658 if ((net_len <= 0) || (net_len > desinbuf.length)) { 659 /* 660 * preposterous length; assume out-of-sync; only recourse 661 * is to close connection, so return 0 662 */ 663 (void) fprintf(stderr, gettext("Read size problem.\n")); 664 return (0); 665 } 666 667 if ((cc = krb5_net_read(kcmd_context, fd, desinbuf.data, net_len)) 668 != net_len) { 669 /* pipe must have closed, return 0 */ 670 (void) fprintf(stderr, 671 gettext("Read error: length received %d " 672 "!= expected %d.\n"), 673 cc, net_len); 674 return (0); 675 } 676 677 /* 678 * Decrypt information 679 */ 680 inputd.enctype = ENCTYPE_UNKNOWN; 681 inputd.ciphertext.length = net_len; 682 inputd.ciphertext.data = (krb5_pointer)desinbuf.data; 683 684 outputd.length = sizeof (storage); 685 outputd.data = (krb5_pointer)storage; 686 687 /* 688 * data is decrypted into the "storage" buffer, which 689 * had better be large enough! 690 */ 691 cc = krb5_c_decrypt(kcmd_context, skey, 692 enc_keyusage_i[secondary], 693 use_ivecs ? encivec_i + secondary : 0, 694 &inputd, &outputd); 695 if (cc) { 696 (void) fprintf(stderr, gettext("Cannot decrypt data " 697 "from network\n")); 698 return (0); 699 } 700 701 store_ptr = storage; 702 nstored = rd_len; 703 if (use_ivecs == B_TRUE) { 704 int rd_len2; 705 rd_len2 = storage[0] & 0xff; 706 rd_len2 <<= 8; rd_len2 |= storage[1] & 0xff; 707 rd_len2 <<= 8; rd_len2 |= storage[2] & 0xff; 708 rd_len2 <<= 8; rd_len2 |= storage[3] & 0xff; 709 if (rd_len2 != rd_len) { 710 /* cleartext length trashed? */ 711 errno = EIO; 712 return (-1); 713 } 714 store_ptr += 4; 715 } 716 /* 717 * Copy only as much data as the input buffer will allow. 718 * The rest is kept in the 'storage' pointer for the next 719 * read. 720 */ 721 if (nstored > len) { 722 (void) memcpy(buf, store_ptr, len); 723 nreturned += len; 724 store_ptr += len; 725 nstored -= len; 726 } else { 727 (void) memcpy(buf, store_ptr, nstored); 728 nreturned += nstored; 729 nstored = 0; 730 } 731 732 return (nreturned); 733 } 734 735 int 736 deswrite(int fd, char *buf, int len, int secondary) 737 { 738 int cc; 739 size_t ret = 0; 740 krb5_data inputd; 741 krb5_enc_data outputd; 742 char tmpbuf[KCMD_BUFSIZ + 8]; 743 char encrbuf[KCMD_BUFSIZ + 8]; 744 unsigned char *len_buf = (unsigned char *)tmpbuf; 745 746 if (!encrypt_flag) 747 return (write(fd, buf, len)); 748 749 if (use_ivecs == B_TRUE) { 750 unsigned char *lenbuf2 = (unsigned char *)tmpbuf; 751 if (len + 4 > sizeof (tmpbuf)) 752 abort(); 753 lenbuf2[0] = (len & 0xff000000) >> 24; 754 lenbuf2[1] = (len & 0xff0000) >> 16; 755 lenbuf2[2] = (len & 0xff00) >> 8; 756 lenbuf2[3] = (len & 0xff); 757 (void) memcpy(tmpbuf + 4, buf, len); 758 759 inputd.data = (krb5_pointer)tmpbuf; 760 inputd.length = len + 4; 761 } else { 762 inputd.data = (krb5_pointer)buf; 763 inputd.length = len; 764 } 765 766 desoutbuf.data = encrbuf; 767 768 if (krb5_c_encrypt_length(kcmd_context, final_enctype, 769 use_ivecs ? (size_t)len + 4 : (size_t)len, &ret)) { 770 desoutbuf.length = ((size_t)-1); 771 goto err; 772 } else { 773 desoutbuf.length = ret; 774 } 775 776 if (desoutbuf.length > MAXSIZE) { 777 (void) fprintf(stderr, gettext("Write size problem.\n")); 778 return (-1); 779 } 780 781 /* 782 * Encrypt information 783 */ 784 outputd.ciphertext.length = desoutbuf.length; 785 outputd.ciphertext.data = (krb5_pointer)desoutbuf.data; 786 787 cc = krb5_c_encrypt(kcmd_context, skey, 788 enc_keyusage_o[secondary], 789 use_ivecs ? encivec_o + secondary : 0, 790 &inputd, &outputd); 791 792 if (cc) { 793 err: 794 (void) fprintf(stderr, gettext("Write encrypt problem.\n")); 795 return (-1); 796 } 797 798 len_buf[0] = (len & 0xff000000) >> 24; 799 len_buf[1] = (len & 0xff0000) >> 16; 800 len_buf[2] = (len & 0xff00) >> 8; 801 len_buf[3] = (len & 0xff); 802 (void) write(fd, len_buf, 4); 803 804 if (write(fd, desoutbuf.data, desoutbuf.length) != desoutbuf.length) { 805 (void) fprintf(stderr, gettext("Could not write " 806 "out all data.\n")); 807 return (-1); 808 } else { 809 return (len); 810 } 811 } 812