1 /* 2 * Copyright 2008 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 /* 462 * This routine is to initialize the desinbuf, desoutbuf and the session key 463 * structures to carry out desread()'s and deswrite()'s successfully 464 */ 465 void 466 init_encrypt(int enc, krb5_context ctxt, enum kcmd_proto protonum, 467 krb5_data *inbuf, krb5_data *outbuf, 468 int amclient, krb5_encrypt_block *block) 469 { 470 krb5_error_code statuscode; 471 size_t blocksize; 472 int i; 473 krb5_error_code ret; 474 475 kcmd_context = ctxt; 476 477 if (enc > 0) { 478 desinbuf.data = inbuf->data; 479 desoutbuf.data = outbuf->data + 4; 480 desinbuf.length = inbuf->length; 481 desoutbuf.length = outbuf->length + 4; 482 encrypt_flag = B_TRUE; 483 } else { 484 encrypt_flag = B_FALSE; 485 return; 486 } 487 488 skey = block->key; 489 final_enctype = skey->enctype; 490 491 enc_keyusage_i[0] = KCMD_KEYUSAGE; 492 enc_keyusage_i[1] = KCMD_KEYUSAGE; 493 enc_keyusage_o[0] = KCMD_KEYUSAGE; 494 enc_keyusage_o[1] = KCMD_KEYUSAGE; 495 496 if (protonum == KCMD_OLD_PROTOCOL) { 497 use_ivecs = B_FALSE; 498 return; 499 } 500 501 use_ivecs = B_TRUE; 502 switch (skey->enctype) { 503 /* 504 * For the DES-based enctypes and the 3DES enctype we 505 * want to use a non-zero IV because that's what we did. 506 * In the future we use different keyusage for each 507 * channel and direction and a fresh cipher state. 508 */ 509 case ENCTYPE_DES_CBC_CRC: 510 case ENCTYPE_DES_CBC_MD4: 511 case ENCTYPE_DES_CBC_MD5: 512 case ENCTYPE_DES3_CBC_SHA1: 513 statuscode = krb5_c_block_size(kcmd_context, final_enctype, 514 &blocksize); 515 if (statuscode) { 516 /* XXX what do I do? */ 517 abort(); 518 } 519 520 encivec_i[0].length = encivec_i[1].length = 521 encivec_o[0].length = encivec_o[1].length = blocksize; 522 523 if ((encivec_i[0].data = malloc(encivec_i[0].length * 4)) 524 == NULL) { 525 /* XXX what do I do? */ 526 abort(); 527 } 528 encivec_i[1].data = encivec_i[0].data + encivec_i[0].length; 529 encivec_o[0].data = encivec_i[1].data + encivec_i[0].length; 530 encivec_o[1].data = encivec_o[0].data + encivec_i[0].length; 531 532 /* is there a better way to initialize this? */ 533 (void) memset(encivec_i[0].data, amclient, blocksize); 534 (void) memset(encivec_o[0].data, 1 - amclient, blocksize); 535 (void) memset(encivec_i[1].data, 2 | amclient, blocksize); 536 (void) memset(encivec_o[1].data, 2 | (1 - amclient), blocksize); 537 break; 538 default: 539 if (amclient) { 540 enc_keyusage_i[0] = 1028; 541 enc_keyusage_i[1] = 1030; 542 enc_keyusage_o[0] = 1032; 543 enc_keyusage_o[1] = 1034; 544 } else { /* amclient */ 545 enc_keyusage_i[0] = 1032; 546 enc_keyusage_i[1] = 1034; 547 enc_keyusage_o[0] = 1028; 548 enc_keyusage_o[1] = 1030; 549 } 550 for (i = 0; i < 2; i++) { 551 ret = krb5_c_init_state(ctxt, 552 skey, enc_keyusage_i[i], 553 &encivec_i[i]); 554 if (ret) 555 goto fail; 556 ret = krb5_c_init_state(ctxt, 557 skey, enc_keyusage_o[i], 558 &encivec_o[i]); 559 if (ret) 560 goto fail; 561 } 562 break; 563 } 564 return; 565 fail: 566 abort(); 567 } 568 569 int 570 desread(int fd, char *buf, int len, int secondary) 571 { 572 int nreturned = 0; 573 long net_len, rd_len; 574 int cc; 575 size_t ret = 0; 576 unsigned char len_buf[4]; 577 krb5_enc_data inputd; 578 krb5_data outputd; 579 580 if (!encrypt_flag) 581 return (read(fd, buf, len)); 582 583 /* 584 * If there is stored data from a previous read, 585 * put it into the output buffer and return it now. 586 */ 587 if (nstored >= len) { 588 (void) memcpy(buf, store_ptr, len); 589 store_ptr += len; 590 nstored -= len; 591 return (len); 592 } else if (nstored) { 593 (void) memcpy(buf, store_ptr, nstored); 594 nreturned += nstored; 595 buf += nstored; 596 len -= nstored; 597 nstored = 0; 598 } 599 600 if ((cc = krb5_net_read(kcmd_context, fd, (char *)len_buf, 4)) != 4) { 601 if ((cc < 0) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) 602 return (cc); 603 /* XXX can't read enough, pipe must have closed */ 604 return (0); 605 } 606 rd_len = ((len_buf[0] << 24) | (len_buf[1] << 16) | 607 (len_buf[2] << 8) | len_buf[3]); 608 609 if (krb5_c_encrypt_length(kcmd_context, final_enctype, 610 use_ivecs ? (size_t)rd_len + 4 : (size_t)rd_len, 611 &ret)) 612 net_len = ((size_t)-1); 613 else 614 net_len = ret; 615 616 if ((net_len <= 0) || (net_len > desinbuf.length)) { 617 /* 618 * preposterous length; assume out-of-sync; only recourse 619 * is to close connection, so return 0 620 */ 621 (void) fprintf(stderr, gettext("Read size problem.\n")); 622 return (0); 623 } 624 625 if ((cc = krb5_net_read(kcmd_context, fd, desinbuf.data, net_len)) 626 != net_len) { 627 /* pipe must have closed, return 0 */ 628 (void) fprintf(stderr, 629 gettext("Read error: length received %d " 630 "!= expected %d.\n"), 631 cc, net_len); 632 return (0); 633 } 634 635 /* 636 * Decrypt information 637 */ 638 inputd.enctype = ENCTYPE_UNKNOWN; 639 inputd.ciphertext.length = net_len; 640 inputd.ciphertext.data = (krb5_pointer)desinbuf.data; 641 642 outputd.length = sizeof (storage); 643 outputd.data = (krb5_pointer)storage; 644 645 /* 646 * data is decrypted into the "storage" buffer, which 647 * had better be large enough! 648 */ 649 cc = krb5_c_decrypt(kcmd_context, skey, 650 enc_keyusage_i[secondary], 651 use_ivecs ? encivec_i + secondary : 0, 652 &inputd, &outputd); 653 if (cc) { 654 (void) fprintf(stderr, gettext("Cannot decrypt data " 655 "from network\n")); 656 return (0); 657 } 658 659 store_ptr = storage; 660 nstored = rd_len; 661 if (use_ivecs == B_TRUE) { 662 int rd_len2; 663 rd_len2 = storage[0] & 0xff; 664 rd_len2 <<= 8; rd_len2 |= storage[1] & 0xff; 665 rd_len2 <<= 8; rd_len2 |= storage[2] & 0xff; 666 rd_len2 <<= 8; rd_len2 |= storage[3] & 0xff; 667 if (rd_len2 != rd_len) { 668 /* cleartext length trashed? */ 669 errno = EIO; 670 return (-1); 671 } 672 store_ptr += 4; 673 } 674 /* 675 * Copy only as much data as the input buffer will allow. 676 * The rest is kept in the 'storage' pointer for the next 677 * read. 678 */ 679 if (nstored > len) { 680 (void) memcpy(buf, store_ptr, len); 681 nreturned += len; 682 store_ptr += len; 683 nstored -= len; 684 } else { 685 (void) memcpy(buf, store_ptr, nstored); 686 nreturned += nstored; 687 nstored = 0; 688 } 689 690 return (nreturned); 691 } 692 int 693 deswrite(int fd, char *buf, int len, int secondary) 694 { 695 int bytes_written; 696 int r; 697 int outlen; 698 char *p; 699 if (!encrypt_flag) 700 return (write(fd, buf, len)); 701 702 bytes_written = 0; 703 while (len > 0) { 704 p = buf + bytes_written; 705 if (len > KCMD8_BUFSIZ) 706 outlen = KCMD8_BUFSIZ; 707 else 708 outlen = len; 709 r = deswrite_compat(fd, p, outlen, secondary); 710 if (r == -1) 711 return (r); 712 bytes_written += r; 713 len -= r; 714 } 715 return (bytes_written); 716 } 717 static int 718 deswrite_compat(int fd, char *buf, int len, int secondary) 719 { 720 int cc; 721 size_t ret = 0; 722 krb5_data inputd; 723 krb5_enc_data outputd; 724 char tmpbuf[KCMD_BUFSIZ + 8]; 725 char encrbuf[KCMD_BUFSIZ + 8]; 726 unsigned char *len_buf = (unsigned char *)tmpbuf; 727 728 if (use_ivecs == B_TRUE) { 729 unsigned char *lenbuf2 = (unsigned char *)tmpbuf; 730 if (len + 4 > sizeof (tmpbuf)) 731 abort(); 732 lenbuf2[0] = (len & 0xff000000) >> 24; 733 lenbuf2[1] = (len & 0xff0000) >> 16; 734 lenbuf2[2] = (len & 0xff00) >> 8; 735 lenbuf2[3] = (len & 0xff); 736 (void) memcpy(tmpbuf + 4, buf, len); 737 738 inputd.data = (krb5_pointer)tmpbuf; 739 inputd.length = len + 4; 740 } else { 741 inputd.data = (krb5_pointer)buf; 742 inputd.length = len; 743 } 744 745 desoutbuf.data = encrbuf; 746 747 if (krb5_c_encrypt_length(kcmd_context, final_enctype, 748 use_ivecs ? (size_t)len + 4 : (size_t)len, &ret)) { 749 desoutbuf.length = ((size_t)-1); 750 goto err; 751 } else { 752 desoutbuf.length = ret; 753 } 754 755 if (desoutbuf.length > MAXSIZE) { 756 (void) fprintf(stderr, gettext("Write size problem.\n")); 757 return (-1); 758 } 759 760 /* 761 * Encrypt information 762 */ 763 outputd.ciphertext.length = desoutbuf.length; 764 outputd.ciphertext.data = (krb5_pointer)desoutbuf.data; 765 766 cc = krb5_c_encrypt(kcmd_context, skey, 767 enc_keyusage_o[secondary], 768 use_ivecs ? encivec_o + secondary : 0, 769 &inputd, &outputd); 770 771 if (cc) { 772 err: 773 (void) fprintf(stderr, gettext("Write encrypt problem.\n")); 774 return (-1); 775 } 776 777 len_buf[0] = (len & 0xff000000) >> 24; 778 len_buf[1] = (len & 0xff0000) >> 16; 779 len_buf[2] = (len & 0xff00) >> 8; 780 len_buf[3] = (len & 0xff); 781 (void) write(fd, len_buf, 4); 782 783 if (write(fd, desoutbuf.data, desoutbuf.length) != desoutbuf.length) { 784 (void) fprintf(stderr, gettext("Could not write " 785 "out all data.\n")); 786 return (-1); 787 } else { 788 return (len); 789 } 790 } 791