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