From d06dab1c3c02ebf99c72dc9c2b82cf06b5b09c58 Mon Sep 17 00:00:00 2001 From: Paul Park Date: Wed, 26 Apr 1995 21:26:17 +0000 Subject: [PATCH] Checking in kpasswd client... git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5516 dc483132-0cff-0310-8789-dd5450dbe970 --- src/kadmin/kpasswd/kpasswd.M | 84 +++++ src/kadmin/kpasswd/kpasswd.c | 573 +++++++++++++++++++++++++++++++++++ 2 files changed, 657 insertions(+) create mode 100644 src/kadmin/kpasswd/kpasswd.M create mode 100644 src/kadmin/kpasswd/kpasswd.c diff --git a/src/kadmin/kpasswd/kpasswd.M b/src/kadmin/kpasswd/kpasswd.M new file mode 100644 index 000000000..7442331a6 --- /dev/null +++ b/src/kadmin/kpasswd/kpasswd.M @@ -0,0 +1,84 @@ +.\" $Source$ +.\" $Author$ +.\" $Id$ +.\" +.\" Copyright 1995 by the Massachusetts Institute of Technology. +.\" +.\" Export of this software from the United States of America may +.\" 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. +.\" +.\" +.TH KPASSWD 1 "Kerberos Version 5.0" "MIT Project Athena" +.SH NAME +kpasswd \- change a user's Kerberos password +.SH SYNOPSIS +.B kpasswd +[ +.B \-m +] [ +.B \-l +language +] [ +.B \-u +.IR username[/instance][@realm] +] +.SH DESCRIPTION +The +.I kpasswd +command is used to change a Kerberos principal's password. + +If the +.I \-n +option is specified, a partially or fully qualified Kerberos principal may +be supplied. Otherwise, the principal name is derived from the identity +of the user invoking the +.I kpasswd +command. + +The +.I \-l +and +.I \-m +flags may be specified to qualify how the administrative server is to issue +messages. The +.I \-l +flag specifies which +.I language +to issue messages in, while the +.I \-m +flag enables MIME-encoded messages. The support of these flags and the +interpretation of the +.I language +paramter is specific to the administrative server. + +.PP +The +.I kpasswd +command prompts for the current Kerberos password, which is verified by the +Kerberos server. If the old password is correct, the user is prompted twice +for the new password. Success or failure is indicated by messages printed +out by +.I kpasswd. + + +.SH FILES +.TP 2i +/tmp/tkt_kpw_[uid] +the temporary credentials cache ([uid] is the decimal UID of the user) for +the lifetime of the password changing operation. +.SH SEE ALSO +kadmin5(8), kadmind5(8) +.SH BUGS diff --git a/src/kadmin/kpasswd/kpasswd.c b/src/kadmin/kpasswd/kpasswd.c new file mode 100644 index 000000000..8239e2e9f --- /dev/null +++ b/src/kadmin/kpasswd/kpasswd.c @@ -0,0 +1,573 @@ +/* + * kadmin/kpasswd/kpasswd.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * 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. + * + */ + +/* + * kpasswd + * change your password with Version 5 Kerberos using the new password + * changing protocol. + */ + +/* + * Include files. + */ +#include +#include +#include + +#include "krb5.h" +#include "adm_defs.h" +#include "adm.h" + +#ifdef USE_STRING_H +#include +#else /* USE_STRING_H */ +#include +#endif /* USE_STRING_H */ + + +/* + * Local definitions. + */ +#define KPWD_MAX_TRIES 4 + +/* + * Local data. + */ +static const char *kpwd_serror_head = "server"; +static const char *kpwd_change_prompt_1 = " Enter new password: "; +static const char *kpwd_change_prompt_2 = "Re-enter new password: "; +static const char *kpwd_old_password_prompt = " Enter old password: "; +static const char *kpwd_old_pwd_name_fmt = "Enter old password for %s: "; + +static const char *kpwd_usage_error_fmt = "%s: usage is %s [-u user] [-m] [-l language].\n"; +static const char *kpwd_extra_args = "extra arguments"; +static const char *kpwd_bad_option_fmt = "%s: unrecognized option -%c.\n"; +static const char *kpwd_no_memory_fmt = "%s: not enough resources to allocate %d bytes for %s.\n"; +static const char *kpwd_bad_client_fmt = "%s: %s%s%s %s not recognized by the server.\n"; +static const char *kpwd_no_server_fmt = "%s: cannot find server for %s.\n"; +static const char *kpwd_incorrect_fmt = "%s: incorrect password\n"; +static const char *kpwd_cant_connect_fmt = "%s: cannot contact server (%s).\n"; +static const char *kpwd_proto_error_fmt = "%s: protocol error during %s request (%s).\n"; +static const char *kpwd_pwproto_unsupp_fmt = "%s: %s request not supported by server.\n"; +static const char *kpwd_pwproto_error = "%s: server error (%s) during %s request.\n"; +static const char *kpwd_pwd_unacceptable = "%s: your new password is unacceptable to the server, %s.\n"; +static const char *kpwd_read_pass_error = "%s: error (%s) reading passwords.\n"; + +static const char *kpwd_password_text = "passwords"; +static const char *kpwd_realm_text = "realm name"; +static const char *kpwd_args_text = "arguments"; + +static const char *kpwd_try_again_text = "try again"; +static const char *kpwd_seeyalater_text = "password not changed"; + +static const char *kpwd_mime_text = "MIME-enable"; +static const char *kpwd_language_text = "set language"; +static const char *kpwd_check_pwd_text = "check password"; +static const char *kpwd_change_pwd_text = "change password"; +static const char *kpwd_quit_text = "quit"; + +static const char *kpwd_you = "you"; +static const char *kpwd_is_second = "are"; +static const char *kpwd_is_third = "is"; +static const char *kpwd_quote = "'"; +static const char *kpwd_null = ""; + +static const char *kpwd_this_realm = "this realm"; + +static const char *kpwd_replies[] = { + "Operation successful", /* KRB5_ADM_SUCCESS */ + "Command not recognized", /* KRB5_ADM_CMD_UNKNOWN */ + "Password unacceptable to server", /* KRB5_ADM_PW_UNACCEPT */ + "Old password incorrect", /* KRB5_ADM_BAD_PW */ + "Invalid ticket (TKT_FLAG_INITIAL not set)",/* KRB5_ADM_NOT_IN_TKT */ + "Server refused password change", /* KRB5_ADM_CANT_CHANGE */ + "Language not supported", /* KRB5_ADM_LANG_NOT_SUPPORTED */ +}; +static const char *kpwd_replies_unknown = "UNKNOWN ERROR"; + +static void +usage(invocation, more_info) + char *invocation; + char *more_info; +{ + if (more_info) + fprintf(stderr, "%s: %s\n", invocation, more_info); + fprintf(stderr, kpwd_usage_error_fmt, invocation, invocation); +} + +static const char * +kpwd_reply_to_string(stat) + krb5_int32 stat; +{ + int index; + const char *rval; + + switch (stat) { + case KRB5_ADM_SUCCESS: + case KRB5_ADM_CMD_UNKNOWN: + case KRB5_ADM_PW_UNACCEPT: + case KRB5_ADM_BAD_PW: + case KRB5_ADM_NOT_IN_TKT: + case KRB5_ADM_CANT_CHANGE: + case KRB5_ADM_LANG_NOT_SUPPORTED: + index = (int) stat; + rval = kpwd_replies[index]; + break; + default: + rval = kpwd_replies_unknown; + break; + } + return(rval); +} + +static void +kpwd_print_sreply(progname, ncomps, complist) + char *progname; + krb5_int32 ncomps; + krb5_data *complist; +{ + krb5_int32 i; + if (ncomps > 0) { + fprintf(stderr, "%s - %s: %s\n", progname, kpwd_serror_head, + complist[0].data); + for (i=1; i 0)) { + usage(argv[0], (error) ? (char *) NULL: kpwd_extra_args); + error++; + if (name) + free(name); + if (language) + free(language); + return(error); + } + + /* Get space for passwords */ + if ( + ((npassword = (char *) malloc(KRB5_ADM_MAX_PASSWORD_LEN)) + == (char *) NULL) || + ((opassword = (char *) malloc(KRB5_ADM_MAX_PASSWORD_LEN)) + == (char *) NULL)) { + fprintf(stderr, kpwd_no_memory_fmt, argv[0], KRB5_ADM_MAX_PASSWORD_LEN, + kpwd_password_text); + if (npassword) + free(npassword); + return(ENOMEM); + } + + /* + * Initialize Kerberos + */ + krb5_init_context(&kcontext); + krb5_init_ets(kcontext); + + /* From now on, all error legs via 'goto cleanup' */ + + if (name) { + int prompt_len; + + prompt_len = strlen(kpwd_old_pwd_name_fmt) - 2 + strlen(name) + 1; + opwd_prompt = (char *) malloc(prompt_len); + if (opwd_prompt) + sprintf(opwd_prompt, kpwd_old_pwd_name_fmt, name); + } + /* + * Establish the connection. + */ + if (kret = krb5_adm_connect(kcontext, + name, + (opwd_prompt) ? + opwd_prompt : kpwd_old_password_prompt, + opassword, + &conn_socket, + &auth_context, + &ccache)) { + switch (kret) { + case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: + fprintf(stderr, kpwd_bad_client_fmt, argv[0], + (name) ? kpwd_quote : kpwd_null, + (name) ? name : kpwd_you, + (name) ? kpwd_quote : kpwd_null, + (name) ? kpwd_is_third : kpwd_is_second); + break; + case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: + fprintf(stderr, kpwd_no_server_fmt, argv[0], + (name) ? name : kpwd_this_realm); + break; + case KRB5KRB_AP_ERR_BAD_INTEGRITY: + fprintf(stderr, kpwd_incorrect_fmt, argv[0]); + break; + default: + fprintf(stderr, kpwd_cant_connect_fmt, argv[0], + error_message(kret)); + break; + } + goto cleanup; + } + + if (opwd_prompt) + free(opwd_prompt); + send_quit = 1; + + /* + * We have the connection - see if we have to send some precursory data. + */ + if (mflag) { + /* + * Need to engage in protocol for MIME setting + */ + krb5_data mime_data; + krb5_int32 mime_status; + krb5_int32 mime_ncomps; + krb5_data *mime_reply; + + mime_data.data = KRB5_ADM_MIME_CMD; + mime_data.length = strlen(mime_data.data); + if ((kret = krb5_send_adm_cmd(kcontext, + &conn_socket, + auth_context, + 1, + &mime_data)) || + (kret = krb5_read_adm_reply(kcontext, + &conn_socket, + auth_context, + &mime_status, + &mime_ncomps, + &mime_reply))) { + fprintf(stderr, kpwd_proto_error_fmt, argv[0], kpwd_mime_text, + error_message(kret)); + send_quit = 0; + goto cleanup; + } + switch (mime_status) { + case KRB5_ADM_SUCCESS: + break; + case KRB5_ADM_CMD_UNKNOWN: + fprintf(stderr, kpwd_pwproto_unsupp_fmt, argv[0], kpwd_mime_text); + if (mime_ncomps > 0) + kpwd_print_sreply(argv[0], mime_ncomps, mime_reply); + break; + default: + fprintf(stderr, kpwd_pwproto_error, argv[0], + kpwd_reply_to_string(mime_status), kpwd_mime_text); + if (mime_ncomps > 0) + kpwd_print_sreply(argv[0], mime_ncomps, mime_reply); + goto cleanup; + } + krb5_free_adm_data(kcontext, mime_ncomps, mime_reply); + } + if (lflag && language) { + /* + * Need to engage in protocol for language setting + */ + krb5_data lang_data[2]; + krb5_int32 lang_status; + krb5_int32 lang_ncomps; + krb5_data *lang_reply; + + lang_data[0].data = KRB5_ADM_LANGUAGE_CMD; + lang_data[0].length = strlen(lang_data[0].data); + lang_data[1].data = language; + lang_data[1].length = strlen(language); + if ((kret = krb5_send_adm_cmd(kcontext, + &conn_socket, + auth_context, + 2, + lang_data)) || + (kret = krb5_read_adm_reply(kcontext, + &conn_socket, + auth_context, + &lang_status, + &lang_ncomps, + &lang_reply))) { + fprintf(stderr, kpwd_proto_error_fmt, argv[0], kpwd_language_text, + error_message(kret)); + send_quit = 0; + goto cleanup; + } + switch (lang_status) { + case KRB5_ADM_SUCCESS: + break; + case KRB5_ADM_CMD_UNKNOWN: + fprintf(stderr, kpwd_pwproto_unsupp_fmt, argv[0], + kpwd_language_text); + if (lang_ncomps > 0) + kpwd_print_sreply(argv[0], lang_ncomps, lang_reply); + break; + default: + fprintf(stderr, kpwd_pwproto_error, argv[0], + kpwd_reply_to_string(lang_status), kpwd_language_text); + if (lang_ncomps > 0) + kpwd_print_sreply(argv[0], lang_ncomps, lang_reply); + goto cleanup; + } + krb5_free_adm_data(kcontext, lang_ncomps, lang_reply); + } + + /* Now - Actually change the password. */ + for (npass_tries = 1; npass_tries <= KPWD_MAX_TRIES; npass_tries++) { + int npass_len; + + npass_len = KRB5_ADM_MAX_PASSWORD_LEN; + if (!(kret = krb5_read_password(kcontext, + kpwd_change_prompt_1, + kpwd_change_prompt_2, + npassword, + &npass_len))) { + krb5_data check_data[2]; + krb5_int32 check_status; + krb5_int32 check_ncomps; + krb5_data *check_reply; + krb5_data set_data[3]; + krb5_int32 set_status; + krb5_int32 set_ncomps; + krb5_int32 *set_reply; + + check_data[0].data = KRB5_ADM_CHECKPW_CMD; + check_data[0].length = strlen(check_data[0].data); + check_data[1].data = npassword; + check_data[1].length = npass_len; + if ((kret = krb5_send_adm_cmd(kcontext, + &conn_socket, + auth_context, + 2, + check_data)) || + (kret = krb5_read_adm_reply(kcontext, + &conn_socket, + auth_context, + &check_status, + &check_ncomps, + &check_reply))) { + fprintf(stderr, kpwd_proto_error_fmt, argv[0], + kpwd_check_pwd_text, error_message(kret)); + send_quit = 0; + error++; + break; + } + if ((check_status != KRB5_ADM_SUCCESS) && + (check_status != KRB5_ADM_PW_UNACCEPT)) { + error++; + fprintf(stderr, kpwd_pwproto_error, argv[0], + kpwd_reply_to_string(check_status), + kpwd_check_pwd_text); + if (check_ncomps > 0) + kpwd_print_sreply(argv[0], check_ncomps, check_reply); + } + + if (check_status == KRB5_ADM_PW_UNACCEPT) { + fprintf(stderr, kpwd_pwd_unacceptable, argv[0], + (npass_tries < KPWD_MAX_TRIES) ? + kpwd_try_again_text : kpwd_seeyalater_text); + if (check_ncomps > 0) + kpwd_print_sreply(argv[0], check_ncomps, check_reply); + if (npass_tries == KPWD_MAX_TRIES) + kret = check_status; + continue; + } + krb5_free_adm_data(kcontext, check_ncomps, check_reply); + if (error) + break; + + /* Now actually change the password */ + set_data[0].data = KRB5_ADM_CHANGEPW_CMD; + set_data[0].length = strlen(set_data[0].data); + set_data[1].data = opassword; + set_data[1].length = strlen(opassword); + set_data[2].data = npassword; + set_data[2].length = npass_len; + if ((kret = krb5_send_adm_cmd(kcontext, + &conn_socket, + auth_context, + 3, + set_data)) || + (kret = krb5_read_adm_reply(kcontext, + &conn_socket, + auth_context, + &set_status, + &set_ncomps, + &set_reply))) { + fprintf(stderr, kpwd_proto_error_fmt, argv[0], + kpwd_change_pwd_text, error_message(kret)); + send_quit = 0; + error++; + break; + } + if (set_status != KRB5_ADM_SUCCESS) { + fprintf(stderr, kpwd_pwproto_error, argv[0], + kpwd_reply_to_string(set_status), + kpwd_change_pwd_text); + if (set_ncomps > 0) + kpwd_print_sreply(argv[0], set_ncomps, set_reply); + error++; + } + krb5_free_adm_data(kcontext, set_ncomps, set_reply); + break; + } + else { + fprintf(stderr, kpwd_read_pass_error, argv[0], + error_message(kret)); + error++; + break; + } + } + + cleanup: + if (kret) + error = kret; + if (language) + free(language); + if (name) + free(name); + + /* Clear and free password storage */ + if (opassword) { + memset(opassword, 0, KRB5_ADM_MAX_PASSWORD_LEN); + krb5_xfree(opassword); + } + if (npassword) { + memset(npassword, 0, KRB5_ADM_MAX_PASSWORD_LEN); + free(npassword); + } + + if (send_quit) { + /* + * Need to send quit command. + */ + krb5_data quit_data; + krb5_int32 quit_status; + krb5_int32 quit_ncomps; + krb5_data *quit_reply; + + quit_data.data = KRB5_ADM_QUIT_CMD; + quit_data.length = strlen(quit_data.data); + if ((kret = krb5_send_adm_cmd(kcontext, + &conn_socket, + auth_context, + 1, + &quit_data)) || + (kret = krb5_read_adm_reply(kcontext, + &conn_socket, + auth_context, + &quit_status, + &quit_ncomps, + &quit_reply))) { + fprintf(stderr, kpwd_proto_error_fmt, argv[0], kpwd_quit_text, + error_message(kret)); + goto done; + } + switch (quit_status) { + case KRB5_ADM_SUCCESS: + break; + case KRB5_ADM_CMD_UNKNOWN: + fprintf(stderr, kpwd_pwproto_unsupp_fmt, argv[0], kpwd_quit_text); + if (quit_ncomps > 0) + kpwd_print_sreply(argv[0], quit_ncomps, quit_reply); + break; + default: + fprintf(stderr, kpwd_pwproto_error, argv[0], + kpwd_reply_to_string(quit_status), kpwd_quit_text); + if (quit_ncomps > 0) + kpwd_print_sreply(argv[0], quit_ncomps, quit_reply); + } + krb5_free_adm_data(kcontext, quit_ncomps, quit_reply); + } + + done: + krb5_adm_disconnect(kcontext, &conn_socket, auth_context, ccache); + krb5_xfree(kcontext); + return(error); +} -- 2.26.2