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