Annotation of src/usr.bin/passwd/krb5_passwd.c, Revision 1.1
1.1 ! deraadt 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 */