1 /* 2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /* 6 * slave/kprop.c 7 * 8 * Copyright 1990,1991 by the Massachusetts Institute of Technology. 9 * All Rights Reserved. 10 * 11 * Export of this software from the United States of America may 12 * require a specific license from the United States Government. 13 * It is the responsibility of any person or organization contemplating 14 * export to obtain such a license before exporting. 15 * 16 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 17 * distribute this software and its documentation for any purpose and 18 * without fee is hereby granted, provided that the above copyright 19 * notice appear in all copies and that both that copyright notice and 20 * this permission notice appear in supporting documentation, and that 21 * the name of M.I.T. not be used in advertising or publicity pertaining 22 * to distribution of the software without specific, written prior 23 * permission. Furthermore if you modify this software you must label 24 * your software as modified software and not distribute it in such a 25 * fashion that it might be confused with the original M.I.T. software. 26 * M.I.T. makes no representations about the suitability of 27 * this software for any purpose. It is provided "as is" without express 28 * or implied warranty. 29 * 30 * 31 */ 32 33 34 #include <errno.h> 35 #include <stdio.h> 36 #include <ctype.h> 37 #include <sys/file.h> 38 #include <signal.h> 39 #include <string.h> 40 #include <sys/types.h> 41 #include <sys/time.h> 42 #include <sys/stat.h> 43 #include <sys/socket.h> 44 #include <netinet/in.h> 45 #include <sys/param.h> 46 #include <netdb.h> 47 #include <fcntl.h> 48 #include <libintl.h> 49 #include <locale.h> 50 #include <k5-int.h> 51 #include "com_err.h" 52 #include "kprop.h" 53 static char *kprop_version = KPROP_PROT_VERSION; 54 55 char *progname = 0; 56 int debug = 0; 57 char *srvtab = 0; 58 char *slave_host; 59 char *realm = 0; 60 char *file = KPROP_DEFAULT_FILE; 61 short port = 0; 62 63 krb5_principal my_principal; /* The Kerberos principal we'll be */ 64 /* running under, initialized in */ 65 /* get_tickets() */ 66 krb5_ccache ccache; /* Credentials cache which we'll be using */ 67 krb5_creds creds; 68 krb5_address sender_addr; 69 krb5_address receiver_addr; 70 71 void PRS 72 (int, char **); 73 void get_tickets 74 (krb5_context); 75 static void usage 76 (void); 77 krb5_error_code open_connection 78 (char *, int *, char *, unsigned int); 79 void kerberos_authenticate 80 (krb5_context, krb5_auth_context *, 81 int, krb5_principal, krb5_creds **); 82 int open_database 83 (krb5_context, char *, int *); 84 void close_database 85 (krb5_context, int); 86 void xmit_database 87 (krb5_context, krb5_auth_context, krb5_creds *, 88 int, int, int); 89 void send_error 90 (krb5_context, krb5_creds *, int, char *, krb5_error_code); 91 void update_last_prop_file 92 (char *, char *); 93 94 static void usage() 95 { 96 fprintf(stderr, 97 gettext 98 ("\nUsage: %s [-r realm] [-f file] [-d] [-P port] [-s srvtab] slave_host\n\n"), 99 progname); 100 exit(1); 101 } 102 103 int 104 main(argc, argv) 105 int argc; 106 char **argv; 107 { 108 int fd, database_fd, database_size; 109 krb5_error_code retval; 110 krb5_context context; 111 krb5_creds *my_creds; 112 krb5_auth_context auth_context; 113 #define ERRMSGSIZ 256 114 char Errmsg[ERRMSGSIZ]; 115 116 (void) setlocale(LC_ALL, ""); 117 118 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 119 #define TEXT_DOMAIN "KPROP_TEST" /* Use this only if it weren't */ 120 #endif 121 122 (void) textdomain(TEXT_DOMAIN); 123 124 retval = krb5_init_context(&context); 125 if (retval) { 126 com_err(argv[0], retval, gettext("while initializing krb5")); 127 exit(1); 128 } 129 PRS(argc, argv); 130 get_tickets(context); 131 132 database_fd = open_database(context, file, &database_size); 133 retval = open_connection(slave_host, &fd, Errmsg, sizeof(Errmsg)); 134 if (retval) { 135 com_err(progname, retval, gettext("%s while opening connection to %s"), 136 Errmsg, slave_host); 137 exit(1); 138 } 139 if (fd < 0) { 140 fprintf(stderr, 141 gettext("%s: %s while opening connection to %s\n"), 142 progname, Errmsg, slave_host); 143 exit(1); 144 } 145 kerberos_authenticate(context, &auth_context, fd, my_principal, 146 &my_creds); 147 xmit_database(context, auth_context, my_creds, fd, database_fd, 148 database_size); 149 update_last_prop_file(slave_host, file); 150 printf(gettext("Database propagation to %s: SUCCEEDED\n"), slave_host); 151 krb5_free_cred_contents(context, my_creds); 152 close_database(context, database_fd); 153 exit(0); 154 } 155 156 void PRS(argc, argv) 157 int argc; 158 char **argv; 159 { 160 int c; 161 register char *word, ch; 162 extern int optind; 163 extern char *optarg; 164 165 progname = argv[0]; 166 while ((c= getopt(argc, argv, "r:f:dP:s:h:")) != EOF) { 167 switch (c) { 168 case 'r': 169 realm = optarg; 170 if (!realm) 171 usage(); 172 break; 173 case 'f': 174 file = optarg; 175 if (!file) 176 usage(); 177 break; 178 case 'd': 179 debug++; 180 break; 181 case 'P': 182 port = atoi(optarg); 183 if (!port) 184 usage(); 185 break; 186 case 's': 187 srvtab = optarg; 188 if (!srvtab) 189 usage(); 190 break; 191 case '?': 192 default: 193 printf (gettext("Error \n")); 194 usage(); 195 } 196 } 197 argc -= optind; 198 argv = &argv[optind]; 199 if (*argv) 200 slave_host = *argv; 201 else 202 usage(); 203 } 204 205 void get_tickets(context) 206 krb5_context context; 207 { 208 char buf[BUFSIZ]; 209 krb5_error_code retval; 210 static char tkstring[] = "/tmp/kproptktXXXXXX"; 211 krb5_keytab keytab = NULL; 212 krb5_get_init_creds_opt opt; 213 char *svcname = NULL; 214 char *def_realm = NULL; 215 char *master_host = NULL; 216 217 218 /* 219 * Figure out what tickets we'll be using to send stuff 220 */ 221 if (realm) { 222 if ((def_realm = strdup(realm)) == NULL) { 223 com_err(progname, ENOMEM, 224 gettext("while allocating default realm name '%s'"), 225 realm); 226 exit(1); 227 } 228 } else { 229 retval = krb5_get_default_realm(context, &def_realm); 230 if (retval) { 231 com_err(progname, retval, 232 gettext("while getting default realm")); 233 exit(1); 234 } 235 } 236 237 /* 238 * Always pick up the master hostname from krb5.conf, as 239 * opposed to picking up the localhost, so we do not get bit 240 * if the master KDC is HA and hence points to a logicalhost. 241 */ 242 retval = kadm5_get_master(context, def_realm, &master_host); 243 if (retval) { 244 free(def_realm); 245 com_err(progname, retval, 246 gettext("while getting admin server fqdn")); 247 exit(1); 248 } 249 250 retval = krb5_sname_to_principal(context, master_host, NULL, 251 KRB5_NT_SRV_HST, &my_principal); 252 253 free(def_realm); 254 free(master_host); 255 if (retval) { 256 com_err(progname, errno, gettext("while setting client principal name")); 257 exit(1); 258 } 259 if (realm) { 260 retval = krb5_set_principal_realm(context, my_principal, realm); 261 if (retval) { 262 com_err(progname, errno, 263 gettext("while setting client principal realm")); 264 exit(1); 265 } 266 } 267 #if 0 268 krb5_princ_type(context, my_principal) = KRB5_NT_PRINCIPAL; 269 #endif 270 271 /* 272 * Initialize cache file which we're going to be using 273 */ 274 (void) mktemp(tkstring); 275 snprintf(buf, sizeof (buf), "FILE:%s", tkstring); 276 277 retval = krb5_cc_resolve(context, buf, &ccache); 278 if (retval) { 279 com_err(progname, retval, gettext("while opening credential cache %s"), 280 buf); 281 exit(1); 282 } 283 284 retval = krb5_cc_initialize(context, ccache, my_principal); 285 if (retval) { 286 com_err (progname, retval, gettext("when initializing cache %s"), 287 buf); 288 exit(1); 289 } 290 291 /* 292 * Get the tickets we'll need. 293 * 294 * Construct the principal name for the slave host. 295 */ 296 memset((char *)&creds, 0, sizeof(creds)); 297 retval = krb5_sname_to_principal(context, 298 slave_host, KPROP_SERVICE_NAME, 299 KRB5_NT_SRV_HST, &creds.server); 300 if (retval) { 301 com_err(progname, errno, gettext("while setting server principal name")); 302 (void) krb5_cc_destroy(context, ccache); 303 exit(1); 304 } 305 if (realm) { 306 retval = krb5_set_principal_realm(context, creds.server, realm); 307 if (retval) { 308 com_err(progname, errno, 309 gettext("while setting server principal realm")); 310 exit(1); 311 } 312 } 313 314 /* 315 * Now fill in the client.... 316 */ 317 retval = krb5_copy_principal(context, my_principal, &creds.client); 318 if (retval) { 319 com_err(progname, retval, gettext("While copying client principal")); 320 (void) krb5_cc_destroy(context, ccache); 321 exit(1); 322 } 323 if (srvtab) { 324 retval = krb5_kt_resolve(context, srvtab, &keytab); 325 if (retval) { 326 com_err(progname, retval, gettext("while resolving keytab")); 327 (void) krb5_cc_destroy(context, ccache); 328 exit(1); 329 } 330 } 331 (void) memset(&opt, 0, sizeof (opt)); 332 krb5_get_init_creds_opt_init(&opt); 333 retval = krb5_unparse_name(context, creds.server, &svcname); 334 if (retval) { 335 com_err(progname, errno, gettext("while parsing svc principal name")); 336 (void) krb5_cc_destroy(context, ccache); 337 exit (1); 338 } 339 retval = krb5_get_init_creds_keytab(context, &creds, creds.client, 340 keytab, 0, svcname, &opt); 341 342 if (svcname) 343 free(svcname); 344 345 if (retval) { 346 com_err(progname, retval, gettext("while getting initial ticket\n")); 347 (void) krb5_cc_destroy(context, ccache); 348 exit(1); 349 } 350 351 if (keytab) 352 (void) krb5_kt_close(context, keytab); 353 354 /* 355 * Now destroy the cache right away --- the credentials we 356 * need will be in my_creds. 357 */ 358 retval = krb5_cc_destroy(context, ccache); 359 if (retval) { 360 com_err(progname, retval, gettext("while destroying ticket cache")); 361 exit(1); 362 } 363 } 364 365 /* SUNW14resync - SOCKET is defed in 1.4 in port-sockets.h */ 366 #ifdef SOCKET 367 #undef SOCKET 368 #endif 369 370 krb5_error_code 371 open_connection(host, fd, Errmsg, ErrmsgSz) 372 char *host; 373 int *fd; 374 char *Errmsg; 375 unsigned int ErrmsgSz; 376 { 377 int s; 378 krb5_error_code retval = 0; 379 380 int socket_length; 381 struct addrinfo hints, *ai, *aitop; 382 struct sockaddr_storage ss; 383 char serv_or_port[NI_MAXSERV]; 384 enum err_types {SOCKET, CONNECT}; 385 int which_err = -1; 386 387 memset(&hints, 0, sizeof(hints)); 388 hints.ai_family = AF_UNSPEC; /* go for either IPv4 or v6 */ 389 hints.ai_socktype = SOCK_STREAM; 390 391 if (port != 0) 392 (void) snprintf(serv_or_port, sizeof(serv_or_port), ("%hu"), 393 port); 394 else 395 strncpy(serv_or_port, KPROP_SERVICE, sizeof(serv_or_port)); 396 397 if (getaddrinfo(host, serv_or_port, &hints, &aitop) != 0) { 398 (void) snprintf(Errmsg, ERRMSGSIZ, gettext("%s: unknown host"), 399 host); 400 *fd = -1; 401 return(0); 402 } 403 404 for (ai = aitop; ai; ai = ai->ai_next) { 405 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 406 continue; 407 408 s = socket(ai->ai_family, SOCK_STREAM, 0); 409 if (s < 0) { 410 which_err = SOCKET; 411 retval = errno; 412 continue; 413 } 414 415 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 && 416 errno != EINPROGRESS) { 417 which_err = CONNECT; 418 retval = errno; 419 close(s); 420 continue; /* fail -- try next */ 421 } 422 423 break; /* success */ 424 } 425 426 if (ai == NULL) { 427 switch (which_err) { 428 case SOCKET: 429 (void) snprintf(Errmsg, ERRMSGSIZ, 430 gettext("in call to socket")); 431 break; 432 case CONNECT: 433 (void) snprintf(Errmsg, ERRMSGSIZ, 434 gettext("in call to connect")); 435 break; 436 default : 437 retval = -1; /* generic error */ 438 (void) snprintf(Errmsg, ERRMSGSIZ, 439 gettext("could not setup network")); 440 break; 441 } 442 if (aitop != NULL) 443 freeaddrinfo(aitop); 444 return(retval); 445 } 446 *fd = s; 447 448 /* 449 * Set receiver_addr and sender_addr. 450 */ 451 if (cvtkaddr((struct sockaddr_storage *)ai->ai_addr, &receiver_addr) 452 == NULL) { 453 retval = errno; 454 com_err(progname, errno, 455 gettext("while converting socket address")); 456 if (aitop != NULL) 457 freeaddrinfo(aitop); 458 return(retval); 459 } 460 if (aitop != NULL) 461 freeaddrinfo(aitop); 462 463 socket_length = sizeof(ss); 464 if (getsockname(s, (struct sockaddr *)&ss, &socket_length) < 0) { 465 retval = errno; 466 close(s); 467 (void) snprintf(Errmsg, ERRMSGSIZ, 468 gettext("in call to getsockname")); 469 return(retval); 470 } 471 472 if (cvtkaddr(&ss, &sender_addr) == NULL) { 473 retval = errno; 474 com_err(progname, errno, 475 gettext("while converting socket address")); 476 return(retval); 477 } 478 479 return(0); 480 } 481 482 483 void kerberos_authenticate(context, auth_context, fd, me, new_creds) 484 krb5_context context; 485 krb5_auth_context *auth_context; 486 int fd; 487 krb5_principal me; 488 krb5_creds ** new_creds; 489 { 490 krb5_error_code retval; 491 krb5_error *error = NULL; 492 krb5_ap_rep_enc_part *rep_result; 493 494 retval = krb5_auth_con_init(context, auth_context); 495 if (retval) 496 exit(1); 497 498 krb5_auth_con_setflags(context, *auth_context, 499 KRB5_AUTH_CONTEXT_DO_SEQUENCE); 500 501 retval = krb5_auth_con_setaddrs(context, *auth_context, &sender_addr, 502 &receiver_addr); 503 if (retval) { 504 com_err(progname, retval, gettext("in krb5_auth_con_setaddrs")); 505 exit(1); 506 } 507 508 retval = krb5_sendauth(context, auth_context, (void *)&fd, 509 kprop_version, me, creds.server, 510 AP_OPTS_MUTUAL_REQUIRED, NULL, &creds, NULL, 511 &error, &rep_result, new_creds); 512 if (retval) { 513 com_err(progname, retval, gettext("while authenticating to server")); 514 if (error) { 515 if (error->error == KRB_ERR_GENERIC) { 516 if (error->text.data) 517 fprintf(stderr, 518 gettext("Generic remote error: %s\n"), 519 error->text.data); 520 } else if (error->error) { 521 com_err(progname, 522 (krb5_error_code) error->error + ERROR_TABLE_BASE_krb5, 523 gettext("signalled from server")); 524 if (error->text.data) 525 fprintf(stderr, 526 gettext("Error text from server: %s\n"), 527 error->text.data); 528 } 529 krb5_free_error(context, error); 530 } 531 exit(1); 532 } 533 krb5_free_ap_rep_enc_part(context, rep_result); 534 } 535 536 char * dbpathname; 537 /* 538 * Open the Kerberos database dump file. Takes care of locking it 539 * and making sure that the .ok file is more recent that the database 540 * dump file itself. 541 * 542 * Returns the file descriptor of the database dump file. Also fills 543 * in the size of the database file. 544 */ 545 int 546 open_database(context, data_fn, size) 547 krb5_context context; 548 char *data_fn; 549 int *size; 550 { 551 int fd; 552 int err; 553 struct stat stbuf, stbuf_ok; 554 char *data_ok_fn; 555 static char ok[] = ".dump_ok"; 556 557 dbpathname = strdup(data_fn); 558 if (!dbpathname) { 559 com_err(progname, ENOMEM, 560 gettext("allocating database file name '%s'"), data_fn); 561 exit(1); 562 } 563 if ((fd = open(dbpathname, O_RDONLY)) < 0) { 564 com_err(progname, errno, gettext("while trying to open %s"), 565 dbpathname); 566 exit(1); 567 } 568 569 err = krb5_lock_file(context, fd, 570 KRB5_LOCKMODE_SHARED|KRB5_LOCKMODE_DONTBLOCK); 571 if (err == EAGAIN || err == EWOULDBLOCK || errno == EACCES) { 572 com_err(progname, 0, gettext("database locked")); 573 exit(1); 574 } else if (err) { 575 com_err(progname, err, gettext("while trying to lock '%s'"), dbpathname); 576 exit(1); 577 } 578 if (fstat(fd, &stbuf)) { 579 com_err(progname, errno, gettext("while trying to stat %s"), 580 data_fn); 581 exit(1); 582 } 583 if ((data_ok_fn = (char *) malloc(strlen(data_fn)+strlen(ok)+1)) 584 == NULL) { 585 com_err(progname, ENOMEM, gettext("while trying to malloc data_ok_fn")); 586 exit(1); 587 } 588 strcpy(data_ok_fn, data_fn); 589 strcat(data_ok_fn, ok); 590 if (stat(data_ok_fn, &stbuf_ok)) { 591 com_err(progname, errno, gettext("while trying to stat %s"), 592 data_ok_fn); 593 free(data_ok_fn); 594 exit(1); 595 } 596 free(data_ok_fn); 597 if (stbuf.st_mtime > stbuf_ok.st_mtime) { 598 com_err(progname, 0, gettext("'%s' more recent than '%s'."), 599 data_fn, data_ok_fn); 600 exit(1); 601 } 602 *size = stbuf.st_size; 603 return(fd); 604 } 605 606 void 607 close_database(context, fd) 608 krb5_context context; 609 int fd; 610 { 611 int err; 612 err = krb5_lock_file(context, fd, KRB5_LOCKMODE_UNLOCK); 613 if (err) 614 com_err(progname, err, gettext("while unlocking database '%s'"), dbpathname); 615 free(dbpathname); 616 (void)close(fd); 617 return; 618 } 619 620 /* 621 * Now we send over the database. We use the following protocol: 622 * Send over a KRB_SAFE message with the size. Then we send over the 623 * database in blocks of KPROP_BLKSIZE, encrypted using KRB_PRIV. 624 * Then we expect to see a KRB_SAFE message with the size sent back. 625 * 626 * At any point in the protocol, we may send a KRB_ERROR message; this 627 * will abort the entire operation. 628 */ 629 void 630 xmit_database(context, auth_context, my_creds, fd, database_fd, 631 in_database_size) 632 krb5_context context; 633 krb5_auth_context auth_context; 634 krb5_creds *my_creds; 635 int fd; 636 int database_fd; 637 int in_database_size; 638 { 639 krb5_int32 sent_size, n; 640 krb5_data inbuf, outbuf; 641 char buf[KPROP_BUFSIZ]; 642 krb5_error_code retval; 643 krb5_error *error; 644 /* These must be 4 bytes */ 645 krb5_ui_4 database_size = in_database_size; 646 krb5_ui_4 send_size; 647 648 /* 649 * Send over the size 650 */ 651 send_size = htonl(database_size); 652 inbuf.data = (char *) &send_size; 653 inbuf.length = sizeof(send_size); /* must be 4, really */ 654 /* KPROP_CKSUMTYPE */ 655 retval = krb5_mk_safe(context, auth_context, &inbuf, 656 &outbuf, NULL); 657 if (retval) { 658 com_err(progname, retval, gettext("while encoding database size")); 659 send_error(context, my_creds, fd, gettext("while encoding database size"), retval); 660 exit(1); 661 } 662 663 retval = krb5_write_message(context, (void *) &fd, &outbuf); 664 if (retval) { 665 krb5_free_data_contents(context, &outbuf); 666 com_err(progname, retval, gettext("while sending database size")); 667 exit(1); 668 } 669 krb5_free_data_contents(context, &outbuf); 670 /* 671 * Initialize the initial vector. 672 */ 673 retval = krb5_auth_con_initivector(context, auth_context); 674 if (retval) { 675 send_error(context, my_creds, fd, 676 gettext("failed while initializing i_vector"), retval); 677 com_err(progname, retval, gettext("while allocating i_vector")); 678 exit(1); 679 } 680 681 /* 682 * Send over the file, block by block.... 683 */ 684 inbuf.data = buf; 685 sent_size = 0; 686 while ((n = read(database_fd, buf, sizeof(buf)))) { 687 inbuf.length = n; 688 retval = krb5_mk_priv(context, auth_context, &inbuf, 689 &outbuf, NULL); 690 if (retval) { 691 snprintf(buf, sizeof (buf), 692 gettext("while encoding database block starting at %d"), 693 sent_size); 694 com_err(progname, retval, buf); 695 send_error(context, my_creds, fd, buf, retval); 696 exit(1); 697 } 698 699 retval = krb5_write_message(context, (void *)&fd,&outbuf); 700 if (retval) { 701 krb5_free_data_contents(context, &outbuf); 702 com_err(progname, retval, 703 gettext("while sending database block starting at %d"), 704 sent_size); 705 exit(1); 706 } 707 krb5_free_data_contents(context, &outbuf); 708 sent_size += n; 709 if (debug) 710 printf(gettext("%d bytes sent.\n"), sent_size); 711 } 712 if (sent_size != database_size) { 713 com_err(progname, 0, gettext("Premature EOF found for database file!")); 714 send_error(context, my_creds, fd,gettext("Premature EOF found for database file!"), 715 KRB5KRB_ERR_GENERIC); 716 exit(1); 717 } 718 719 /* 720 * OK, we've sent the database; now let's wait for a success 721 * indication from the remote end. 722 */ 723 retval = krb5_read_message(context, (void *) &fd, &inbuf); 724 if (retval) { 725 com_err(progname, retval, 726 gettext("while reading response from server")); 727 exit(1); 728 } 729 /* 730 * If we got an error response back from the server, display 731 * the error message 732 */ 733 if (krb5_is_krb_error(&inbuf)) { 734 retval = krb5_rd_error(context, &inbuf, &error); 735 if (retval) { 736 com_err(progname, retval, 737 gettext("while decoding error response from server")); 738 exit(1); 739 } 740 if (error->error == KRB_ERR_GENERIC) { 741 if (error->text.data) 742 fprintf(stderr, 743 gettext("Generic remote error: %s\n"), 744 error->text.data); 745 } else if (error->error) { 746 com_err(progname, 747 (krb5_error_code) error->error + 748 ERROR_TABLE_BASE_krb5, 749 gettext("signalled from server")); 750 if (error->text.data) 751 fprintf(stderr, 752 gettext("Error text from server: %s\n"), 753 error->text.data); 754 } 755 krb5_free_error(context, error); 756 exit(1); 757 } 758 759 retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL); 760 if (retval) { 761 com_err(progname, retval, 762 gettext("while decoding final size packet from server")); 763 exit(1); 764 } 765 766 memcpy((char *)&send_size, outbuf.data, sizeof(send_size)); 767 send_size = ntohl(send_size); 768 if (send_size != database_size) { 769 com_err(progname, 0, 770 gettext("Kpropd sent database size %d, expecting %d"), 771 send_size, database_size); 772 exit(1); 773 } 774 free(outbuf.data); 775 free(inbuf.data); 776 } 777 778 void 779 send_error(context, my_creds, fd, err_text, err_code) 780 krb5_context context; 781 krb5_creds *my_creds; 782 int fd; 783 char *err_text; 784 krb5_error_code err_code; 785 { 786 krb5_error error; 787 const char *text; 788 krb5_data outbuf; 789 790 memset((char *)&error, 0, sizeof(error)); 791 krb5_us_timeofday(context, &error.ctime, &error.cusec); 792 error.server = my_creds->server; 793 error.client = my_principal; 794 error.error = err_code - ERROR_TABLE_BASE_krb5; 795 if (error.error > 127) 796 error.error = KRB_ERR_GENERIC; 797 if (err_text) 798 text = err_text; 799 else 800 text = error_message(err_code); 801 error.text.length = strlen(text) + 1; 802 error.text.data = malloc((unsigned int) error.text.length); 803 if (error.text.data) { 804 strcpy(error.text.data, text); 805 if (!krb5_mk_error(context, &error, &outbuf)) { 806 (void) krb5_write_message(context, (void *)&fd,&outbuf); 807 krb5_free_data_contents(context, &outbuf); 808 } 809 free(error.text.data); 810 } 811 } 812 813 void update_last_prop_file(hostname, file_name) 814 char *hostname; 815 char *file_name; 816 { 817 /* handle slave locking/failure stuff */ 818 char *file_last_prop; 819 int fd; 820 static char last_prop[]=".last_prop"; 821 822 if ((file_last_prop = (char *)malloc(strlen(file_name) + 823 strlen(hostname) + 1 + 824 strlen(last_prop) + 1)) == NULL) { 825 com_err(progname, ENOMEM, 826 gettext("while allocating filename for update_last_prop_file")); 827 return; 828 } 829 strcpy(file_last_prop, file_name); 830 831 /* 832 * If a nondefault file name was specified then we should not add an 833 * extraneous host name to the file name given that a file name could 834 * have already specified a host name and therefore would be redundant. 835 */ 836 if (strcmp(file_name, KPROP_DEFAULT_FILE) == 0) { 837 strcat(file_last_prop, "."); 838 strcat(file_last_prop, hostname); 839 } 840 strcat(file_last_prop, last_prop); 841 if ((fd = THREEPARAMOPEN(file_last_prop, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) { 842 com_err(progname, errno, 843 gettext("while creating 'last_prop' file, '%s'"), 844 file_last_prop); 845 free(file_last_prop); 846 return; 847 } 848 write(fd, "", 1); 849 free(file_last_prop); 850 close(fd); 851 return; 852 } 853