/*
 * This software may now be redistributed outside the US.
 *
 */

/* 
  Copyright (C) 1989 by the Massachusetts Institute of Technology

   Export of this software from the United States of America is assumed
   to require a specific license from the United States Government.
   It is the responsibility of any person or organization contemplating
   export to obtain such a license before exporting.

WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
distribute this software and its documentation for any purpose and
without fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright notice and
this permission notice appear in supporting documentation, and that
the name of M.I.T. not be used in advertising or publicity pertaining
to distribution of the software without specific, written prior
permission.  M.I.T. makes no representations about the suitability of
this software for any purpose.  It is provided "as is" without express
or implied warranty.

  */

/*
 * change your password with kerberos
 */

#include "kadm_locl.h"

RCSID("$Header: /afs/nada.kth.se/src/packages/kth-krb/SourceRepository/krb4/kadmin/kpasswd.c,v 1.4 1995/10/27 10:56:40 bg Exp $");

#ifdef NOENCRYPTION
#define read_long_pw_string placebo_read_pw_string
#else
#define read_long_pw_string des_read_pw_string
#endif
    
static void
usage(int value)
{
    fprintf(stderr, "Usage: ");
    fprintf(stderr, "kpasswd [-h ] [-n user] [-i instance] [-r realm] ");
    fprintf(stderr, "[-u fullname]\n");
    exit(value);
}

static void
go_home(char *str, int x)
{
    fprintf(stderr, str, x);
    (void) dest_tkt();
    exit(1);
}

#if 1
/*
 * Check if pw is a good password.  Then return NULL, otherwise
 * return a string with an explanation
 */
char *FascistCheck(char *pw, char *dictpath)
{
  return 0;			/* FOR NOW ALL PASSWORDS ARE GOOD! */
}
#endif

#define DICTPATH "/usr/local/lib/pw_dict"

static char *
check_pw (char *pword)
{
     if (strlen(pword) == 0)
	  return "Null passwords are not allowed";
     return FascistCheck (pword, DICTPATH);
}

static void
get_pw_new_key(des_cblock (*new_key), char *name, char *inst,
	       char *realm,
	       int print_realm)
                  		/* True if realm was give on cmdline */
{
    char ppromp[40+ANAME_SZ+INST_SZ+REALM_SZ]; /* for the password prompt */
    char pword[MAX_KPW_LEN];	               /* storage for the password */
    char npromp[40+ANAME_SZ+INST_SZ+REALM_SZ]; /* for the password prompt */
    
    char local_realm[REALM_SZ];
    int status;
    char *expl;
    
    /*
     * We don't care about failure; this is to determine whether or
     * not to print the realm in the prompt for a new password. 
     */
    (void) krb_get_lrealm(local_realm, 1);
    
    if (strcmp(local_realm, realm))
	print_realm++;
    
    (void) sprintf(ppromp,"Old password for %s%s%s%s%s:",
		   name, *inst ? "." : "", inst,
		   print_realm ? "@" : "", print_realm ? realm : "");
    if (read_long_pw_string(pword, sizeof(pword)-1, ppromp, 0)) {
	fprintf(stderr, "Error reading old password.\n");
	exit(1);
    }

    if ((status = krb_get_pw_in_tkt(name, inst, realm, PWSERV_NAME, 
				    KADM_SINST, 1, pword)) != KSUCCESS) {
	if (status == INTK_BADPW) {
	    printf("Incorrect old password.\n");
	    exit(0);
	}
	else {
	    fprintf(stderr, "Kerberos error: %s\n", krb_err_txt[status]);
	    exit(1);
	}
    }
    bzero(pword, sizeof(pword));
    do {
	(void) sprintf(npromp,"New Password for %s%s%s%s%s:",
		       name, *inst ? "." : "", inst,
		       print_realm ? "@" : "", print_realm ? realm : "");
	if (read_long_pw_string(pword, sizeof(pword)-1, npromp, 1))
	    go_home("Error reading new password, password unchanged.\n",0);
	expl = check_pw (pword);
	if (expl)
	    printf("Bad password: %s\n", expl);
    } while (expl);
    
#ifdef NOENCRYPTION
    bzero((char *) new_key, sizeof(des_cblock));
    new_key[0] = (unsigned char) 1;
#else
   (void) des_string_to_key(pword, new_key);
#endif
    bzero(pword, sizeof(pword));
}

int
main(int argc, char **argv)
{
    char name[ANAME_SZ];	/* name of user */
    char inst[INST_SZ];		/* instance of user */
    char realm[REALM_SZ];	/* realm of user */
    char default_name[ANAME_SZ];
    char default_inst[INST_SZ];
    char default_realm[REALM_SZ];
    int realm_given = 0;	/* True if realm was give on cmdline */
    int use_default = 1;	/* True if we should use default name */
    struct passwd *pw;
    int status;			/* return code */
    des_cblock new_key;
    int c;
    char tktstring[MaxPathLen];
    
    bzero(name, sizeof(name));
    bzero(inst, sizeof(inst));
    bzero(realm, sizeof(realm));
    
    if (krb_get_tf_fullname(TKT_FILE, default_name, default_inst, 
			    default_realm) != KSUCCESS) {
	pw = getpwuid((int) getuid());
	if (pw)
	    (void) strcpy(default_name, pw->pw_name);
	else
	    /* seems like a null name is kinda silly */
	    (void) strcpy(default_name, ""); 
	strcpy(default_inst, "");
	if (krb_get_lrealm(default_realm, 1) != KSUCCESS)
	    strcpy(default_realm, "NO.DEFAULT.REALM");
    }

    while ((c = getopt(argc, argv, "u:n:i:r:h")) != EOF) {
	switch (c) {
	  case 'u':
	    if ((status = kname_parse(name, inst, realm, optarg))) {
		fprintf(stderr, "Kerberos error: %s\n", krb_err_txt[status]);
		exit(2);
	    }
	    if (realm[0])
		realm_given++;
	    else
		if (krb_get_lrealm(realm, 1) != KSUCCESS)
		    strcpy(realm, "NO.DEFAULT.REALM");
	    break;
	  case 'n':
	    if (k_isname(optarg))
		(void) strncpy(name, optarg, sizeof(name) - 1);
	    else {
		fprintf(stderr, "Bad name: %s\n", optarg);
		usage(1);
	    }
	    break;
	  case 'i':
	    if (k_isinst(optarg))
		(void) strncpy(inst, optarg, sizeof(inst) - 1);
	    else {
		fprintf(stderr, "Bad instance: %s\n", optarg);
		usage(1);
	    }
	    (void) strcpy(inst, optarg);
	    break;
	  case 'r':
	    if (k_isrealm(optarg)) {
		(void) strncpy(realm, optarg, sizeof(realm) - 1);
		realm_given++; 
	    }
	    else {
		fprintf(stderr, "Bad realm: %s\n", optarg);
		usage(1);
	    }
	    break;
	  case 'h':
	    usage(0);
	    break;
	  default:
	    usage(1);
	    break;
	}
	use_default = 0;
    }
    if (optind < argc)
	usage(1);

    if (use_default) {
	strcpy(name, default_name);
	strcpy(inst, default_inst);
	strcpy(realm, default_realm);
    }
    else {
	if (!name[0])
	    strcpy(name, default_name);
	if (!realm[0])
	    strcpy(realm, default_realm);
    }

    (void) sprintf(tktstring, "/tmp/tkt_cpw_%d",(int)getpid());
    krb_set_tkt_string(tktstring);
    
    get_pw_new_key(&new_key, name, inst, realm, realm_given);
    
    if ((status = kadm_init_link("changepw", KRB_MASTER, realm)) 
	!= KADM_SUCCESS) 
	com_err(argv[0], status, "while initializing");
    else if ((status = kadm_change_pw(new_key)) != KADM_SUCCESS)
	com_err(argv[0], status, " attempting to change password.");

    if (status != KADM_SUCCESS)
	fprintf(stderr,"Password NOT changed.\n");
    else
	printf("Password changed.\n");

    (void) dest_tkt();
    if (status)
	exit(2);
    else 
	exit(0);
}
