1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 /*static char sccsid[] = "from: @(#)krb_passwd.c 5.4 (Berkeley) 3/1/91";*/ 36 static char rcsid[] = "$Id: krb5_passwd.c,v 1.1 1994/07/27 03:28:16 brezak Exp $"; 37 #endif /* not lint */ 38 39 #ifdef KERBEROS5 40 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <sys/time.h> 44 #include <sys/resource.h> 45 #include <netinet/in.h> 46 #include <netdb.h> 47 #include <signal.h> 48 #include <pwd.h> 49 #include <errno.h> 50 #include <stdio.h> 51 #include <string.h> 52 #include <stdlib.h> 53 #include <krb5/adm_defs.h> 54 #include <krb5/krb5.h> 55 #include <krb5/kdb.h> 56 #include <krb5/kdb_dbm.h> 57 #include <krb5/ext-proto.h> 58 #include <krb5/los-proto.h> 59 #include <krb5/asn1.h> 60 #include <krb5/config.h> 61 #include <krb5/base-defs.h> 62 #include <krb5/asn.1/encode.h> 63 64 #include <krb5/widen.h> 65 66 #include <krb5/adm_err.h> 67 #include <krb5/errors.h> 68 #include <krb5/kdb5_err.h> 69 #include <krb5/krb5_err.h> 70 71 static krb5_error_code get_first_ticket __P((krb5_ccache, krb5_principal)); 72 static krb5_error_code print_and_choose_password __P((char *, krb5_data *)); 73 static krb5_error_code adm5_init_link __P((krb5_data *, int *)); 74 75 struct sockaddr_in local_sin, remote_sin; 76 77 krb5_creds my_creds; 78 79 extern char *krb5_default_pwd_prompt1; 80 81 /* 82 * Try no preauthentication first; then try the encrypted timestamp 83 */ 84 int preauth_search_list[] = { 85 0, 86 KRB5_PADATA_ENC_TIMESTAMP, 87 -1 88 }; 89 90 krb_passwd() 91 { 92 static void finish(); 93 krb5_ccache cache = NULL; 94 char cache_name[255]; 95 krb5_flags cc_flags; 96 krb5_address local_addr, foreign_addr; 97 struct passwd *pw; 98 krb5_principal client, server; 99 char default_name[256]; 100 char *client_name; /* Single string representation of client id */ 101 krb5_data requested_realm; 102 char *local_realm; 103 char input_string[768]; 104 krb5_error_code retval; /* return code */ 105 int local_socket; 106 int c, count; 107 krb5_error *err_ret; 108 krb5_ap_rep_enc_part *rep_ret; 109 kadmin_requests rd_priv_resp; 110 krb5_checksum send_cksum; 111 int cksum_alloc = 0; 112 krb5_data msg_data, inbuf; 113 krb5_int32 seqno; 114 char *new_password; 115 int new_pwsize; 116 krb5_data *decodable_pwd_string; 117 int i, j; 118 static struct rlimit rl = { 0, 0 }; 119 120 #ifdef KRB_NONETWORK 121 extern int networked(); 122 int krb_secure; 123 struct stat statbuf; 124 #endif 125 126 #ifdef KRB_NONETWORK /* Allow or Disallow Remote Clients to Modify Passwords */ 127 /* 128 * If a Client Modifies a Password using kpasswd on this host 129 * from a remote host or network terminal, the Password selected 130 * is transmitted across the network in Cleartext. 131 * 132 * The systems administrator can disallow "remote" kpasswd usage by 133 * creating the file "/etc/krb.secure" 134 */ 135 krb_secure = 0; 136 /* 137 * First check to see if the file /etc/krb.secure exists. 138 * If it does then krb_secure to 1. 139 */ 140 141 if (stat("/etc/krb.secure", &statbuf) == 0) krb_secure = 1; 142 143 /* 144 * Check to see if this process is tied to a physical terminal. 145 * Network() verifies the terminal device is not a pseudo tty 146 */ 147 if (networked() && krb_secure) { 148 fprintf(stderr,"passwd: Sorry but you cannot %s from a\n", argv[0]); 149 fprintf(stderr," pseudo tty terminal.\n"); 150 retval = 1; 151 goto finish; 152 } 153 #endif 154 155 /* (3 * 255) + 1 (/) + 1 (@) + 1 (NULL) */ 156 if ((client_name = (char *) calloc (1, (3 * 256))) == NULL) { 157 fprintf(stderr, "passwd: No Memory for Client_name\n"); 158 retval = 1; 159 goto finish; 160 } 161 162 if ((requested_realm.data = (char *) calloc (1, 256)) == NULL) { 163 fprintf(stderr, "passwd: No Memory for realm_name\n"); 164 retval = 1; 165 free(client_name); 166 goto finish; 167 } 168 169 (void)signal(SIGHUP, SIG_IGN); 170 (void)signal(SIGINT, SIG_IGN); 171 (void)signal(SIGTSTP, SIG_IGN); 172 173 if (setrlimit(RLIMIT_CORE, &rl) < 0) { 174 (void)fprintf(stderr, 175 "passwd: setrlimit: %s\n", strerror(errno)); 176 return(1); 177 } 178 179 krb5_init_ets(); 180 memset((char *) default_name, 0, sizeof(default_name)); 181 182 /* Identify Default Credentials Cache */ 183 if ((retval = krb5_cc_default(&cache))) { 184 fprintf(stderr, "passwd: Error while getting default ccache.\n"); 185 goto finish; 186 } 187 188 /* 189 * Attempt to Modify Credentials Cache 190 * retval == 0 ==> ccache Exists - Use It 191 * retval == ENOENT ==> No Entries, but ccache Exists 192 * retval != 0 ==> Assume ccache does NOT Exist 193 */ 194 cc_flags = 0; 195 if ((retval = krb5_cc_set_flags(cache, cc_flags))) { 196 /* Search passwd file for client */ 197 pw = getpwuid((int) getuid()); 198 if (pw) { 199 (void) strcpy(default_name, pw->pw_name); 200 } 201 else { 202 fprintf(stderr, 203 "passwd: Unable to Identify Customer from Password File\n"); 204 retval = 1; 205 goto finish; 206 } 207 208 /* Use this to get default_realm and format client_name */ 209 if ((retval = krb5_parse_name(default_name, &client))) { 210 fprintf(stderr, "passwd: Unable to Parse Client Name\n"); 211 goto finish; 212 } 213 214 if ((retval = krb5_unparse_name(client, &client_name))) { 215 fprintf(stderr, "passwd: Unable to Parse Client Name\n"); 216 goto finish; 217 } 218 219 requested_realm.length = client->realm.length; 220 memcpy((char *) requested_realm.data, 221 (char *) client->realm.data, 222 requested_realm.length); 223 } 224 else { 225 /* Read Client from Cache */ 226 if ((retval = krb5_cc_get_principal(cache, (krb5_principal *) &client))) { 227 fprintf(stderr, "passwd: Unable to Read Customer Credentials File\n"); 228 goto finish; 229 } 230 231 if ((retval = krb5_unparse_name(client, &client_name))) { 232 fprintf(stderr, "passwd: Unable to Parse Client Name\n"); 233 goto finish; 234 } 235 236 requested_realm.length = client->realm.length; 237 memcpy((char *) requested_realm.data, 238 (char *) client->realm.data, 239 requested_realm.length); 240 241 (void) krb5_cc_close(cache); 242 } 243 244 /* Create credential cache for changepw */ 245 (void) sprintf(cache_name, "FILE:/tmp/tkt_cpw_%d", getpid()); 246 247 if ((retval = krb5_cc_resolve(cache_name, &cache))) { 248 fprintf(stderr, "passwd: Unable to Resolve Cache: %s\n", cache_name); 249 } 250 251 if ((retval = krb5_cc_initialize(cache, client))) { 252 fprintf(stderr, "passwd: Error initializing cache: %s\n", cache_name); 253 goto finish; 254 } 255 256 /* 257 * Verify User by Obtaining Initial Credentials prior to Initial Link 258 */ 259 if ((retval = get_first_ticket(cache, client))) { 260 goto finish; 261 } 262 263 /* Initiate Link to Server */ 264 if ((retval = adm5_init_link(&requested_realm, &local_socket))) { 265 goto finish; 266 } 267 268 #define SIZEOF_INADDR sizeof(struct in_addr) 269 270 /* V4 kpasswd Protocol Hack */ 271 { 272 int msg_length = 0; 273 274 retval = krb5_net_write(local_socket, (char *) &msg_length + 2, 2); 275 if (retval < 0) { 276 fprintf(stderr, "passwd: krb5_net_write failure\n"); 277 goto finish; 278 } 279 } 280 281 local_addr.addrtype = ADDRTYPE_INET; 282 local_addr.length = SIZEOF_INADDR ; 283 local_addr.contents = (krb5_octet *)&local_sin.sin_addr; 284 285 foreign_addr.addrtype = ADDRTYPE_INET; 286 foreign_addr.length = SIZEOF_INADDR ; 287 foreign_addr.contents = (krb5_octet *)&remote_sin.sin_addr; 288 289 /* compute checksum, using CRC-32 */ 290 if (!(send_cksum.contents = (krb5_octet *) 291 malloc(krb5_checksum_size(CKSUMTYPE_CRC32)))) { 292 fprintf(stderr, "passwd: Insufficient Memory while Allocating Checksum\n"); 293 goto finish; 294 } 295 cksum_alloc++; 296 /* choose some random stuff to compute checksum from */ 297 if (retval = krb5_calculate_checksum(CKSUMTYPE_CRC32, 298 ADM_CPW_VERSION, 299 strlen(ADM_CPW_VERSION), 300 0, 301 0, /* if length is 0, crc-32 doesn't 302 use the seed */ 303 &send_cksum)) { 304 fprintf(stderr, "Error while Computing Checksum: %s\n", 305 error_message(retval)); 306 goto finish; 307 } 308 309 /* call Kerberos library routine to obtain an authenticator, 310 pass it over the socket to the server, and obtain mutual 311 authentication. */ 312 313 if ((retval = krb5_sendauth((krb5_pointer) &local_socket, 314 ADM_CPW_VERSION, 315 my_creds.client, 316 my_creds.server, 317 AP_OPTS_MUTUAL_REQUIRED, 318 &send_cksum, 319 0, 320 cache, 321 &seqno, 322 0, /* don't need a subsession key */ 323 &err_ret, 324 &rep_ret))) { 325 fprintf(stderr, "passwd: Error while performing sendauth: %s\n", 326 error_message(retval)); 327 goto finish; 328 } 329 330 /* Get credentials : to use for safe and private messages */ 331 if (retval = krb5_get_credentials(0, cache, &my_creds)){ 332 fprintf(stderr, "passwd: Error Obtaining Credentials: %s\n", 333 error_message(retval)); 334 goto finish; 335 } 336 337 /* Read back what the server has to say... */ 338 if (retval = krb5_read_message(&local_socket, &inbuf)){ 339 fprintf(stderr, "passwd: Read Message Error: %s\n", 340 error_message(retval)); 341 goto finish; 342 } 343 if ((inbuf.length != 2) || (inbuf.data[0] != KADMIND) || 344 (inbuf.data[1] != KADMSAG)){ 345 fprintf(stderr, "passwd: Invalid ack from admin server.\n"); 346 goto finish; 347 } 348 349 inbuf.data[0] = KPASSWD; 350 inbuf.data[1] = CHGOPER; 351 inbuf.length = 2; 352 353 if ((retval = krb5_mk_priv(&inbuf, 354 ETYPE_DES_CBC_CRC, 355 &my_creds.keyblock, 356 &local_addr, 357 &foreign_addr, 358 seqno, 359 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, 360 0, 361 0, 362 &msg_data))) { 363 fprintf(stderr, "passwd: Error during First Message Encoding: %s\n", 364 error_message(retval)); 365 goto finish; 366 } 367 free(inbuf.data); 368 369 /* write private message to server */ 370 if (krb5_write_message(&local_socket, &msg_data)){ 371 fprintf(stderr, "passwd: Write Error During First Message Transmission\n"); 372 retval = 1; 373 goto finish; 374 } 375 free(msg_data.data); 376 377 (void)signal(SIGHUP, finish); 378 (void)signal(SIGINT, finish); 379 380 #ifdef MACH_PASS /* Machine-generated Passwords */ 381 /* Ok Now let's get the private message */ 382 if (retval = krb5_read_message(&local_socket, &inbuf)){ 383 fprintf(stderr, "passwd: Read Error During First Reply: %s\n", 384 error_message(retval)); 385 retval = 1; 386 goto finish; 387 } 388 389 if ((retval = krb5_rd_priv(&inbuf, 390 &my_creds.keyblock, 391 &foreign_addr, 392 &local_addr, 393 rep_ret->seq_number, 394 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, 395 0, 396 0, 397 &msg_data))) { 398 fprintf(stderr, "passwd: Error during First Read Decoding: %s\n", 399 error_message(retval)); 400 goto finish; 401 } 402 free(inbuf.data); 403 #endif 404 405 if ((new_password = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == NULL) { 406 fprintf(stderr, "passwd: Unable to Allocate Space for New Password\n"); 407 goto finish; 408 } 409 410 #ifdef MACH_PASS /* Machine-generated passwords */ 411 /* Offer Client Password Choices */ 412 if ((retval = print_and_choose_password(new_password, 413 &msg_data))) { 414 (void) memset((char *) new_password, 0, ADM_MAX_PW_LENGTH+1); 415 free(new_password); 416 goto finish; 417 } 418 #else 419 new_pwsize = ADM_MAX_PW_LENGTH+1; 420 if ((retval = krb5_read_password("New Kerberos password: ", 421 "Retype new Kerberos password: ", 422 new_password, 423 &new_pwsize))) { 424 fprintf(stderr, "\nError while reading new password for '%s'\n", 425 client_name); 426 (void) memset((char *) new_password, 0, ADM_MAX_PW_LENGTH+1); 427 free(new_password); 428 goto finish; 429 } 430 #endif 431 432 inbuf.data = new_password; 433 inbuf.length = strlen(new_password); 434 435 if ((retval = krb5_mk_priv(&inbuf, 436 ETYPE_DES_CBC_CRC, 437 &my_creds.keyblock, 438 &local_addr, 439 &foreign_addr, 440 seqno, 441 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, 442 0, 443 0, 444 &msg_data))) { 445 fprintf(stderr, "passwd: Error during Second Message Encoding: %s\n", 446 error_message(retval)); 447 goto finish; 448 } 449 memset(inbuf.data,0,inbuf.length); 450 free(inbuf.data); 451 452 /* write private message to server */ 453 if (krb5_write_message(&local_socket, &msg_data)){ 454 fprintf(stderr, "passwd: Write Error During Second Message Transmission\n"); 455 retval = 1; 456 goto finish; 457 } 458 free(msg_data.data); 459 460 /* Ok Now let's get the private message */ 461 if (retval = krb5_read_message(&local_socket, &inbuf)){ 462 fprintf(stderr, "passwd: Read Error During Second Reply: %s\n", 463 error_message(retval)); 464 retval = 1; 465 goto finish; 466 } 467 468 if ((retval = krb5_rd_priv(&inbuf, 469 &my_creds.keyblock, 470 &foreign_addr, 471 &local_addr, 472 rep_ret->seq_number, 473 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, 474 0, 475 0, 476 &msg_data))) { 477 fprintf(stderr, "passwd: Error during Second Read Decoding :%s\n", 478 error_message(retval)); 479 goto finish; 480 } 481 482 rd_priv_resp.appl_code = msg_data.data[0]; 483 rd_priv_resp.oper_code = msg_data.data[1]; 484 rd_priv_resp.retn_code = msg_data.data[2]; 485 if (msg_data.length > 3 && msg_data.data[3]) { 486 rd_priv_resp.message = malloc(msg_data.length - 2); 487 if (rd_priv_resp.message) { 488 memcpy(rd_priv_resp.message, msg_data.data + 3, 489 msg_data.length - 3); 490 rd_priv_resp.message[msg_data.length - 3] = 0; 491 } 492 } else 493 rd_priv_resp.message = NULL; 494 495 496 free(inbuf.data); 497 free(msg_data.data); 498 if (rd_priv_resp.appl_code == KPASSWD) { 499 if (rd_priv_resp.retn_code == KPASSBAD) { 500 if (rd_priv_resp.message) 501 fprintf(stderr, "passwd: %s\n", rd_priv_resp.message); 502 else 503 fprintf(stderr, "passwd: Server returned KPASSBAD.\n"); 504 } else if (rd_priv_resp.retn_code != KPASSGOOD) 505 fprintf(stderr, "passwd: Server returned unknown kerberos code.\n"); 506 } else 507 fprintf(stderr, "passwd: Server returned bad application code %d\n", 508 rd_priv_resp.appl_code); 509 510 if (rd_priv_resp.message) 511 free(rd_priv_resp.message); 512 513 finish: 514 (void) krb5_cc_destroy(cache); 515 516 free(client_name); 517 free(requested_realm.data); 518 if (cksum_alloc) free(send_cksum.contents); 519 if (retval) { 520 fprintf(stderr, "passwd: Protocol Failure - Password NOT changed\n"); 521 exit(1); 522 } 523 524 exit(0); 525 } 526 527 528 529 krb5_data cpwname = { 530 sizeof(CPWNAME)-1, 531 CPWNAME 532 }; 533 534 static krb5_error_code 535 get_first_ticket(cache, client) 536 krb5_ccache cache; 537 krb5_principal client; 538 { 539 char prompt[255]; /* for the password prompt */ 540 char verify_prompt[255]; /* Verification Prompt if Desired */ 541 char pword[ADM_MAX_PW_LENGTH+1]; /* storage for the password */ 542 int pword_length = sizeof(pword); 543 char *old_password; 544 int old_pwsize; 545 int i; 546 547 krb5_address **my_addresses; 548 549 char *client_name; 550 char local_realm[255]; 551 krb5_error_code retval; 552 553 if ((retval = krb5_unparse_name(client, &client_name))) { 554 fprintf(stderr, "Unable to Unparse Client Name\n"); 555 return(1); 556 } 557 558 (void) printf("Changing Kerberos password for %s\n", client_name); 559 560 if ((retval = krb5_os_localaddr(&my_addresses))) { 561 fprintf(stderr, "passwd: Unable to Get Customers Address\n"); 562 return(1); 563 } 564 565 memset((char *) &my_creds, 0, sizeof(my_creds)); 566 567 my_creds.client = client; 568 569 if ((retval = krb5_build_principal_ext(&my_creds.server, 570 client->realm.length, 571 client->realm.data, 572 cpwname.length, /* 6 */ 573 cpwname.data, /* "kadmin" */ 574 client->realm.length, 575 /* instance is local realm */ 576 client->realm.data, 577 0))) { 578 fprintf(stderr, "Error %s while building server name\n"); 579 return(1); 580 } 581 582 583 if ((old_password = (char *) calloc (1, 255)) == NULL) { 584 fprintf(stderr, "passwd: No Memory for Retrieving old password\n"); 585 return(1); 586 } 587 588 old_pwsize = 255; 589 if ((retval = krb5_read_password("Old kerberos password: ", 590 0, 591 old_password, 592 &old_pwsize))) { 593 fprintf(stderr, "\nError while reading password for '%s'\n", 594 client_name); 595 return(1); 596 } 597 598 /* Build Request for Initial Credentials */ 599 for (i=0; preauth_search_list[i] >= 0; i++) { 600 retval = krb5_get_in_tkt_with_password( 601 0, /* options */ 602 my_addresses, 603 /* do random preauth */ 604 preauth_search_list[i], 605 ETYPE_DES_CBC_CRC, /* etype */ 606 KEYTYPE_DES, 607 old_password, 608 cache, 609 &my_creds, 610 0); 611 if (retval != KRB5KDC_PREAUTH_FAILED && 612 retval != KRB5KRB_ERR_GENERIC) 613 break; 614 } 615 616 if (retval) { 617 fprintf(stderr, "passwd: Unable to Get Initial Credentials : %s\n", 618 error_message(retval)); 619 } 620 621 /* Do NOT Forget to zap password */ 622 memset((char *) old_password, 0, old_pwsize); 623 free(old_password); 624 memset((char *) pword, 0, sizeof(pword)); 625 return(retval); 626 } 627 628 #ifdef MACH_PASS /* Machine-generated Passwords */ 629 static krb5_error_code 630 print_and_choose_password(new_password, decodable_pwd_string) 631 char * new_password; 632 krb5_data *decodable_pwd_string; 633 { 634 krb5_error_code retval; 635 krb5_pwd_data *pwd_data; 636 passwd_phrase_element **next_passwd_phrase_element; 637 char prompt[255]; 638 char *verify_prompt = 0; 639 int i, j, k; 640 int legit_pswd = 0; /* Assume No Legitimate Password */ 641 char *password_list[ADM_MAX_PW_CHOICES]; 642 char verification_passwd[ADM_MAX_PW_LENGTH+1]; 643 char phrase_in[ADM_MAX_PHRASE_LENGTH]; 644 int new_passwd_length; 645 char *ptr; 646 int verify = 0; /* Do Not Request Password Selection Verification */ 647 int ok = 0; 648 649 #define free_local_password_list() \ 650 { for ( k = 0; k < i && k < ADM_MAX_PW_CHOICES; k++) { \ 651 (void) memset(password_list[k], 0, ADM_MAX_PW_LENGTH); \ 652 free(password_list[k]); } \ 653 } 654 655 /* Decode Password and Phrase Information Obtained from krb5_rd_priv */ 656 if ((retval = decode_krb5_pwd_data(decodable_pwd_string , &pwd_data))) { 657 fprintf(stderr, "passwd: Unable to Decode Passwords and Phrases\n"); 658 fprintf(stderr, " Notify your System Administrator or the Kerberos Administrator\n"); 659 return(1); 660 } 661 662 next_passwd_phrase_element = pwd_data->element; 663 /* Display List in 5 Password/Phrase Increments up to MAX Iterations */ 664 memset((char *) phrase_in, 0, ADM_MAX_PHRASE_LENGTH); 665 for ( j = 0; j <= ADM_MAX_PW_ITERATIONS; j++) { 666 if (j == ADM_MAX_PW_ITERATIONS) { 667 fprintf(stderr, "passwd: Sorry - You Have Exceeded the List of Choices (%d) Allowed for Password\n", 668 ADM_MAX_PW_ITERATIONS * ADM_MAX_PW_CHOICES); 669 fprintf(stderr, " Modification. You Must Repeat this Operation in order to Successfully\n"); 670 fprintf(stderr, " Change your Password.\n"); 671 break; 672 } 673 674 display_print: 675 printf("Choose a password from the following list:\n"); 676 677 printf("\nPassword Remembrance Aid\n"); 678 679 /* Print Passwords and Assistance Phrases List */ 680 for ( i = 0; i < ADM_MAX_PW_CHOICES; i++){ 681 if ((password_list[i] = (char *) calloc (1, 682 ADM_MAX_PW_LENGTH + 1)) == NULL) { 683 fprintf(stderr, "passwd: Unable to Allocate Password List.\n"); 684 return(1); 685 } 686 687 memcpy(password_list[i], 688 (*next_passwd_phrase_element)->passwd->data, 689 (*next_passwd_phrase_element)->passwd->length); 690 printf("%s ", password_list[i]); 691 692 memcpy((char *) phrase_in, 693 (*next_passwd_phrase_element)->phrase->data, 694 (*next_passwd_phrase_element)->phrase->length); 695 for ( k = 0; 696 k < 50 && k < (*next_passwd_phrase_element)->phrase->length; 697 k++) { 698 printf("%c", phrase_in[k]); 699 } 700 for ( k = k; 701 k < 70 && k < (*next_passwd_phrase_element)->phrase->length; 702 k++) { 703 if (phrase_in[k] == ' ') { 704 printf("\n "); 705 k++; 706 break; 707 } else { 708 printf("%c", phrase_in[k]); 709 } 710 } 711 for ( k = k; 712 k < (*next_passwd_phrase_element)->phrase->length; 713 k++) { 714 printf("%c", phrase_in[k]); 715 } 716 printf("\n"); 717 memset((char *) phrase_in, 0, ADM_MAX_PHRASE_LENGTH); 718 next_passwd_phrase_element++; 719 } 720 721 sprintf(prompt, 722 "\nEnter Password Selection or a <CR> to get new list: "); 723 724 new_passwd_length = ADM_MAX_PW_LENGTH+1; 725 /* Read New Password from Terminal (Do Not Print on Screen) */ 726 if ((retval = krb5_read_password(&prompt[0], 0, 727 new_password, &new_passwd_length))) { 728 fprintf(stderr, 729 "passwd: Error Reading Password Input or Input Aborted\n"); 730 free_local_password_list(); 731 break;; 732 } 733 734 /* Check for <CR> ==> Provide a New List */ 735 if (new_passwd_length == 0) continue; 736 737 /* Check that Selection is from List - Server also does this */ 738 legit_pswd = 0; 739 for (i = 0; i < ADM_MAX_PW_CHOICES && !legit_pswd; i++) 740 if ((retval = memcmp(new_password, 741 password_list[i], 8)) == 0) { 742 legit_pswd++; 743 } 744 free_local_password_list(); 745 746 if (!(legit_pswd)) { 747 printf("\07\07Password must be from the specified list "); 748 printf("- Try Again\n"); 749 } 750 751 if (legit_pswd) break; /* Exit Loop */ 752 } /* ADM_MAX_PW_CHOICES Loop */ 753 754 if (!(legit_pswd)) return (1); 755 756 return(0); /* SUCCESS */ 757 } 758 #endif 759 760 static krb5_error_code 761 adm5_init_link(realm_of_server, local_socket) 762 krb5_data *realm_of_server; 763 int * local_socket; 764 { 765 struct servent *service_process; /* service we will talk to */ 766 struct hostent *local_host; /* us */ 767 struct hostent *remote_host; /* host we will talk to */ 768 struct sockaddr *sockaddr_list; 769 770 char **hostlist; 771 772 int host_count; 773 int namelen; 774 int i, count; 775 776 krb5_error_code retval; 777 778 /* clear out the structure first */ 779 (void) memset((char *)&remote_sin, 0, sizeof(remote_sin)); 780 781 if ((service_process = getservbyname(CPW_SNAME, "tcp")) == NULL) { 782 fprintf(stderr, "passwd: Unable to find Service (%s) Check services file\n", 783 CPW_SNAME); 784 return(1); 785 } 786 787 /* Copy the Port Number */ 788 remote_sin.sin_port = service_process->s_port; 789 790 hostlist = 0; 791 792 /* Identify all Hosts Associated with this Realm */ 793 if ((retval = krb5_get_krbhst (realm_of_server, &hostlist))) { 794 fprintf(stderr, "passwd: Unable to Determine Server Name\n"); 795 return(1); 796 } 797 798 for (i=0; hostlist[i]; i++); 799 800 count = i; 801 802 if (count == 0) { 803 host_count = 0; 804 fprintf(stderr, "passwd: No hosts found\n"); 805 return(1); 806 } 807 808 for (i=0; hostlist[i]; i++) { 809 remote_host = gethostbyname(hostlist[i]); 810 if (remote_host != 0) { 811 812 /* set up the address of the foreign socket for connect() */ 813 remote_sin.sin_family = remote_host->h_addrtype; 814 (void) memcpy((char *) &remote_sin.sin_addr, 815 (char *) remote_host->h_addr, 816 sizeof(remote_host->h_addr)); 817 break; /* Only Need one */ 818 } 819 } 820 821 free ((char *)hostlist); 822 823 /* open a TCP socket */ 824 *local_socket = socket(PF_INET, SOCK_STREAM, 0); 825 if (*local_socket < 0) { 826 fprintf(stderr, "passwd: Cannot Open Socket\n"); 827 return(1); 828 } 829 /* connect to the server */ 830 if (connect(*local_socket, (struct sockaddr *)&remote_sin, sizeof(remote_sin)) < 0) { 831 fprintf(stderr, "passwd: Cannot Connect to Socket\n"); 832 close(*local_socket); 833 return(1); 834 } 835 836 /* find out who I am, now that we are connected and therefore bound */ 837 namelen = sizeof(local_sin); 838 if (getsockname(*local_socket, 839 (struct sockaddr *) &local_sin, &namelen) < 0) { 840 fprintf(stderr, "passwd: Cannot Perform getsockname\n"); 841 close(*local_socket); 842 return(1); 843 } 844 return(0); 845 } 846 847 static void 848 finish() 849 { 850 exit(1); 851 } 852 853 #ifdef KRB_NONETWORK 854 #include <utmp.h> 855 856 #ifndef MAXHOSTNAME 857 #define MAXHOSTNAME 64 858 #endif 859 860 int utfile; /* Global utfile file descriptor for BSD version 861 of setutent, getutline, and endutent */ 862 863 #if !defined(SYSV) && !defined(UMIPS) /* Setutent, Endutent, and getutline 864 routines for non System V Unix 865 systems */ 866 #include <fcntl.h> 867 868 void setutent() 869 { 870 utfile = open("/etc/utmp",O_RDONLY); 871 } 872 873 struct utmp * getutline(utmpent) 874 struct utmp *utmpent; 875 { 876 static struct utmp tmputmpent; 877 int found = 0; 878 while ( read(utfile,&tmputmpent,sizeof(struct utmp)) > 0 ){ 879 if ( strcmp(tmputmpent.ut_line,utmpent->ut_line) == 0){ 880 #ifdef NO_UT_HOST 881 if ( ( 1) && 882 #else 883 if ( (strcmp(tmputmpent.ut_host,"") == 0) && 884 #endif 885 (strcmp(tmputmpent.ut_name,"") == 0)) continue; 886 found = 1; 887 break; 888 } 889 } 890 if (found) 891 return(&tmputmpent); 892 return((struct utmp *) 0); 893 } 894 895 void endutent() 896 { 897 close(utfile); 898 } 899 #endif /* not SYSV */ 900 901 902 int network_connected() 903 { 904 struct utmp utmpent; 905 struct utmp retutent, *tmpptr; 906 char *display_indx; 907 char currenthost[MAXHOSTNAME]; 908 char *username,*tmpname; 909 910 911 /* Macro for pseudo_tty */ 912 #define pseudo_tty(ut) \ 913 ((strncmp((ut).ut_line, "tty", 3) == 0 && ((ut).ut_line[3] == 'p' \ 914 || (ut).ut_line[3] == 'q' \ 915 || (ut).ut_line[3] == 'r' \ 916 || (ut).ut_line[3] == 's'))\ 917 || (strncmp((ut).ut_line, "pty", 3) == 0)) 918 919 /* Check to see if getlogin returns proper name */ 920 if ( (tmpname = (char *) getlogin()) == (char *) 0) return(1); 921 username = (char *) malloc(strlen(tmpname) + 1); 922 if ( username == (char *) 0) return(1); 923 strcpy(username,tmpname); 924 925 /* Obtain tty device for controlling tty of current process.*/ 926 strncpy(utmpent.ut_line,ttyname(0) + strlen("/dev/"), 927 sizeof(utmpent.ut_line)); 928 929 /* See if this device is currently listed in /etc/utmp under 930 calling user */ 931 #ifdef SYSV 932 utmpent.ut_type = USER_PROCESS; 933 #define ut_name ut_user 934 #endif 935 setutent(); 936 while ( (tmpptr = (struct utmp *) getutline(&utmpent)) 937 != ( struct utmp *) 0) { 938 939 /* If logged out name and host will be empty */ 940 if ((strcmp(tmpptr->ut_name,"") == 0) && 941 #ifdef NO_UT_HOST 942 ( 1)) continue; 943 #else 944 (strcmp(tmpptr->ut_host,"") == 0)) continue; 945 #endif 946 else break; 947 } 948 if ( tmpptr == (struct utmp *) 0) { 949 endutent(); 950 return(1); 951 } 952 bcopy((char *)&retutent, (char *)tmpptr, sizeof(struct utmp)); 953 endutent(); 954 #ifdef DEBUG 955 #ifdef NO_UT_HOST 956 printf("User %s on line %s :\n", 957 retutent.ut_name,retutent.ut_line); 958 #else 959 printf("User %s on line %s connected from host :%s:\n", 960 retutent.ut_name,retutent.ut_line,retutent.ut_host); 961 #endif 962 #endif 963 if (strcmp(retutent.ut_name,username) != 0) { 964 return(1); 965 } 966 967 968 /* If this is not a pseudo tty then everything is OK */ 969 if (! pseudo_tty(retutent)) return(0); 970 971 /* OK now the work begins there is an entry in utmp and 972 the device is a pseudo tty. */ 973 974 /* Check if : is in hostname if so this is xwindow display */ 975 976 if (gethostname(currenthost,sizeof(currenthost))) return(1); 977 #ifdef NO_UT_HOST 978 display_indx = (char *) 0; 979 #else 980 display_indx = (char *) strchr(retutent.ut_host,':'); 981 #endif 982 if ( display_indx != (char *) 0) { 983 /* 984 We have X window application here. The host field should have 985 the form => local_system_name:0.0 or :0.0 986 if the window is being displayed on the local system. 987 */ 988 #ifdef NO_UT_HOST 989 return(1); 990 #else 991 if (strncmp(currenthost,retutent.ut_host, 992 (display_indx - retutent.ut_host)) != 0) return(1); 993 else return(0); 994 #endif 995 } 996 997 /* Host field is empty or is not X window entry. At this point 998 we can't trust that the pseudo tty is not connected to a 999 networked process so let's return 1. 1000 */ 1001 return(1); 1002 } 1003 1004 int networked() 1005 { 1006 return(network_connected()); 1007 } 1008 #endif 1009 1010 #endif /* KERBEROS5 */ 1011