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