f8cfa01382
Submitted by: joerg
637 lines
16 KiB
C
637 lines
16 KiB
C
/*
|
|
* $Source$
|
|
* $Author$
|
|
*
|
|
* Copyright 1988 by the Massachusetts Institute of Technology.
|
|
*
|
|
* For copying and distribution information, please see the file
|
|
* Copyright.MIT.
|
|
*
|
|
* Kerberos database administrator's tool.
|
|
*
|
|
* The default behavior of kadmin is if the -m option is given
|
|
* on the commandline, multiple requests are allowed to be given
|
|
* with one entry of the admin password (until the tickets expire).
|
|
* If you do not want this to be an available option, compile with
|
|
* NO_MULTIPLE defined.
|
|
*/
|
|
|
|
#if 0
|
|
#ifndef lint
|
|
static char rcsid_kadmin_c[] =
|
|
"BonesHeader: /afs/athena.mit.edu/astaff/project/kerberos/src/kadmin/RCS/kadmin.c,v 4.5 89/09/26 14:17:54 qjb Exp ";
|
|
#endif lint
|
|
#endif
|
|
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <sys/param.h>
|
|
#include <pwd.h>
|
|
#include <ss/ss.h>
|
|
#include <com_err.h>
|
|
#include <krb_err.h>
|
|
#include <kadm.h>
|
|
|
|
#define BAD_PW 1
|
|
#define GOOD_PW 0
|
|
#define FUDGE_VALUE 15 /* for ticket expiration time */
|
|
#define PE_NO 0
|
|
#define PE_YES 1
|
|
#define PE_UNSURE 2
|
|
|
|
/* for get_password, whether it should do the swapping...necessary for
|
|
using vals structure, unnecessary for change_pw requests */
|
|
#define DONTSWAP 0
|
|
#define SWAP 1
|
|
|
|
static void do_init(int argc, char *argv[]);
|
|
void clean_up(void);
|
|
int get_password(unsigned long *low, unsigned long *high, char *prompt,
|
|
int byteswap);
|
|
int get_admin_password(void);
|
|
int princ_exists(char *name, char *instance, char *realm);
|
|
|
|
extern ss_request_table admin_cmds;
|
|
|
|
static char myname[ANAME_SZ];
|
|
static char default_realm[REALM_SZ]; /* default kerberos realm */
|
|
static char krbrlm[REALM_SZ]; /* current realm being administered */
|
|
#ifndef NO_MULTIPLE
|
|
static int multiple = 0; /* Allow multiple requests per ticket */
|
|
#endif
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int sci_idx;
|
|
int code;
|
|
char tktstring[MAXPATHLEN];
|
|
|
|
void quit();
|
|
|
|
sci_idx = ss_create_invocation("admin", "2.0", (char *) NULL,
|
|
&admin_cmds, &code);
|
|
if (code) {
|
|
ss_perror(sci_idx, code, "creating invocation");
|
|
exit(1);
|
|
}
|
|
(void) sprintf(tktstring, "/tmp/tkt_adm_%d",getpid());
|
|
krb_set_tkt_string(tktstring);
|
|
|
|
do_init(argc, argv);
|
|
|
|
printf("Welcome to the Kerberos Administration Program, version 2\n");
|
|
printf("Type \"help\" if you need it.\n");
|
|
ss_listen(sci_idx, &code);
|
|
printf("\n");
|
|
quit();
|
|
exit(0);
|
|
}
|
|
|
|
int
|
|
setvals(vals, string)
|
|
Kadm_vals *vals;
|
|
char *string;
|
|
{
|
|
char realm[REALM_SZ];
|
|
int status = KADM_SUCCESS;
|
|
|
|
bzero(vals, sizeof(*vals));
|
|
bzero(realm, sizeof(realm));
|
|
|
|
SET_FIELD(KADM_NAME,vals->fields);
|
|
SET_FIELD(KADM_INST,vals->fields);
|
|
if ((status = kname_parse(vals->name, vals->instance, realm, string))) {
|
|
printf("kerberos error: %s\n", krb_err_txt[status]);
|
|
return status;
|
|
}
|
|
if (!realm[0])
|
|
strcpy(realm, default_realm);
|
|
if (strcmp(realm, krbrlm)) {
|
|
strcpy(krbrlm, realm);
|
|
if ((status = kadm_init_link(PWSERV_NAME, KRB_MASTER, krbrlm))
|
|
!= KADM_SUCCESS)
|
|
printf("kadm error for realm %s: %s\n",
|
|
krbrlm, error_message(status));
|
|
}
|
|
if (status)
|
|
return 1;
|
|
else
|
|
return KADM_SUCCESS;
|
|
}
|
|
|
|
void
|
|
change_password(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
Kadm_vals old, new;
|
|
int status;
|
|
char pw_prompt[BUFSIZ];
|
|
|
|
if (argc != 2) {
|
|
printf("Usage: change_password loginname\n");
|
|
return;
|
|
}
|
|
|
|
if (setvals(&old, argv[1]) != KADM_SUCCESS)
|
|
return;
|
|
|
|
new = old;
|
|
|
|
SET_FIELD(KADM_DESKEY,new.fields);
|
|
|
|
if (princ_exists(old.name, old.instance, krbrlm) != PE_NO) {
|
|
/* get the admin's password */
|
|
if (get_admin_password() != GOOD_PW)
|
|
return;
|
|
|
|
/* get the new password */
|
|
(void) sprintf(pw_prompt, "New password for %s:", argv[1]);
|
|
|
|
if (get_password(&new.key_low, &new.key_high,
|
|
pw_prompt, SWAP) == GOOD_PW) {
|
|
status = kadm_mod(&old, &new);
|
|
if (status == KADM_SUCCESS) {
|
|
printf("Password changed for %s.\n", argv[1]);
|
|
} else {
|
|
printf("kadmin: %s\nwhile changing password for %s",
|
|
error_message(status), argv[1]);
|
|
}
|
|
} else
|
|
printf("Error reading password; password unchanged\n");
|
|
bzero((char *)&new, sizeof(new));
|
|
#ifndef NO_MULTIPLE
|
|
if (!multiple)
|
|
clean_up();
|
|
#endif
|
|
}
|
|
else
|
|
printf("kadmin: Principal does not exist.\n");
|
|
return;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
change_admin_password(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
des_cblock newkey;
|
|
unsigned long low, high;
|
|
int status;
|
|
char prompt_pw[BUFSIZ];
|
|
|
|
if (argc != 1) {
|
|
printf("Usage: change_admin_password\n");
|
|
return;
|
|
}
|
|
/* get the admin's password */
|
|
if (get_admin_password() != GOOD_PW)
|
|
return;
|
|
|
|
(void) sprintf(prompt_pw, "New password for %s.admin:",myname);
|
|
if (get_password(&low, &high, prompt_pw, DONTSWAP) == GOOD_PW) {
|
|
bcopy((char *)&low,(char *) newkey,4);
|
|
bcopy((char *)&high, (char *)(((long *) newkey) + 1),4);
|
|
low = high = 0L;
|
|
if ((status = kadm_change_pw(newkey)) == KADM_SUCCESS)
|
|
printf("Admin password changed\n");
|
|
else
|
|
printf("kadm error: %s\n",error_message(status));
|
|
bzero((char *)newkey, sizeof(newkey));
|
|
} else
|
|
printf("Error reading password; password unchanged\n");
|
|
#ifndef NO_MULTIPLE
|
|
if (!multiple)
|
|
clean_up();
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
void
|
|
add_new_key(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
Kadm_vals new;
|
|
char pw_prompt[BUFSIZ];
|
|
int status;
|
|
|
|
if (argc != 2) {
|
|
printf("Usage: add_new_key user_name.\n");
|
|
return;
|
|
}
|
|
if (setvals(&new, argv[1]) != KADM_SUCCESS)
|
|
return;
|
|
|
|
SET_FIELD(KADM_DESKEY,new.fields);
|
|
|
|
if (princ_exists(new.name, new.instance, krbrlm) != PE_YES) {
|
|
/* get the admin's password */
|
|
if (get_admin_password() != GOOD_PW)
|
|
return;
|
|
|
|
/* get the new password */
|
|
(void) sprintf(pw_prompt, "Password for %s:", argv[1]);
|
|
|
|
if (get_password(&new.key_low, &new.key_high,
|
|
pw_prompt, SWAP) == GOOD_PW) {
|
|
status = kadm_add(&new);
|
|
if (status == KADM_SUCCESS) {
|
|
printf("%s added to database.\n", argv[1]);
|
|
} else {
|
|
printf("kadm error: %s\n",error_message(status));
|
|
}
|
|
} else
|
|
printf("Error reading password; %s not added\n",argv[1]);
|
|
bzero((char *)&new, sizeof(new));
|
|
#ifndef NO_MULTIPLE
|
|
if (!multiple)
|
|
clean_up();
|
|
#endif
|
|
}
|
|
else
|
|
printf("kadmin: Principal already exists.\n");
|
|
return;
|
|
}
|
|
|
|
void
|
|
get_entry(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int status;
|
|
u_char fields[4];
|
|
Kadm_vals vals;
|
|
|
|
if (argc != 2) {
|
|
printf("Usage: get_entry username\n");
|
|
return;
|
|
}
|
|
|
|
bzero(fields, sizeof(fields));
|
|
|
|
SET_FIELD(KADM_NAME,fields);
|
|
SET_FIELD(KADM_INST,fields);
|
|
SET_FIELD(KADM_EXPDATE,fields);
|
|
SET_FIELD(KADM_ATTR,fields);
|
|
SET_FIELD(KADM_MAXLIFE,fields);
|
|
|
|
if (setvals(&vals, argv[1]) != KADM_SUCCESS)
|
|
return;
|
|
|
|
|
|
if (princ_exists(vals.name, vals.instance, krbrlm) != PE_NO) {
|
|
/* get the admin's password */
|
|
if (get_admin_password() != GOOD_PW)
|
|
return;
|
|
|
|
if ((status = kadm_get(&vals, fields)) == KADM_SUCCESS)
|
|
prin_vals(&vals);
|
|
else
|
|
printf("kadm error: %s\n",error_message(status));
|
|
|
|
#ifndef NO_MULTIPLE
|
|
if (!multiple)
|
|
clean_up();
|
|
#endif
|
|
}
|
|
else
|
|
printf("kadmin: Principal does not exist.\n");
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
help(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
if (argc == 1) {
|
|
printf("Welcome to the Kerberos administration program.");
|
|
printf("Type \"?\" to get\n");
|
|
printf("a list of requests that are available. You can");
|
|
printf(" get help on each of\n");
|
|
printf("the commands by typing \"help command_name\".");
|
|
printf(" Some functions of this\n");
|
|
printf("program will require an \"admin\" password");
|
|
printf(" from you. This is a password\n");
|
|
printf("private to you, that is used to authenticate");
|
|
printf(" requests from this\n");
|
|
printf("program. You can change this password with");
|
|
printf(" the \"change_admin_password\"\n");
|
|
printf("(or short form \"cap\") command. Good Luck! \n");
|
|
} else if (!strcmp(argv[1], "change_password") ||
|
|
!strcmp(argv[1], "cpw")) {
|
|
printf("Usage: change_password user_name.\n");
|
|
printf("\n");
|
|
printf("user_name is the name of the user whose password");
|
|
printf(" you wish to change. \n");
|
|
printf("His/her password is changed in the kerberos database\n");
|
|
printf("When this command is issued, first the \"Admin\"");
|
|
printf(" password will be prompted\n");
|
|
printf("for and if correct the user's new password will");
|
|
printf(" be prompted for (twice with\n");
|
|
printf("appropriate comparison). Note: No minimum password");
|
|
printf(" length restrictions apply, but\n");
|
|
printf("longer passwords are more secure.\n");
|
|
} else if (!strcmp(argv[1], "change_admin_password") ||
|
|
!strcmp(argv[1], "cap")) {
|
|
printf("Usage: change_admin_password.\n");
|
|
printf("\n");
|
|
printf("This command takes no arguments and is used");
|
|
printf(" to change your private\n");
|
|
printf("\"Admin\" password. It will first prompt for");
|
|
printf(" the (current) \"Admin\"\n");
|
|
printf("password and then ask for the new password");
|
|
printf(" by prompting:\n");
|
|
printf("\n");
|
|
printf("New password for <Your User Name>.admin:\n");
|
|
printf("\n");
|
|
printf("Enter the new admin password that you desire");
|
|
printf(" (it will be asked for\n");
|
|
printf("twice to avoid errors).\n");
|
|
} else if (!strcmp(argv[1], "add_new_key") ||
|
|
!strcmp(argv[1], "ank")) {
|
|
printf("Usage: add_new_key user_name.\n");
|
|
printf("\n");
|
|
printf("user_name is the name of a new user to put");
|
|
printf(" in the kerberos database. Your\n");
|
|
printf("\"Admin\" password and the user's password");
|
|
printf(" are prompted for. The user's\n");
|
|
printf("password will be asked for");
|
|
printf(" twice to avoid errors.\n");
|
|
} else if (!strcmp(argv[1], "get_entry") ||
|
|
!strcmp(argv[1], "get")) {
|
|
printf("Usage: get_entry user_name.\n");
|
|
printf("\n");
|
|
printf("user_name is the name of a user whose");
|
|
printf(" entry you wish to review. Your\n");
|
|
printf("\"Admin\" password is prompted for. ");
|
|
printf(" The key field is not filled in, for\n");
|
|
printf("security reasons.\n");
|
|
} else if (!strcmp(argv[1], "destroy_tickets") ||
|
|
!strcmp(argv[1], "dest")) {
|
|
printf("Usage: destroy_tickets\n");
|
|
printf("\n");
|
|
printf("Destroy your admin tickets. This will");
|
|
printf(" cause you to be prompted for your\n");
|
|
printf("admin password on your next request.\n");
|
|
} else if (!strcmp(argv[1], "list_requests") ||
|
|
!strcmp(argv[1], "lr") ||
|
|
!strcmp(argv[1], "?")) {
|
|
printf("Usage: list_requests\n");
|
|
printf("\n");
|
|
printf("This command lists what other commands are");
|
|
printf(" currently available.\n");
|
|
} else if (!strcmp(argv[1], "exit") ||
|
|
!strcmp(argv[1], "quit") ||
|
|
!strcmp(argv[1], "q")) {
|
|
printf("Usage: quit\n");
|
|
printf("\n");
|
|
printf("This command exits this program.\n");
|
|
} else {
|
|
printf("Sorry there is no such command as %s.", argv[1]);
|
|
printf(" Type \"help\" for more information. \n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
go_home(str,x)
|
|
char *str;
|
|
int x;
|
|
{
|
|
fprintf(stderr, "%s: %s\n", str, error_message(x));
|
|
clean_up();
|
|
exit(1);
|
|
}
|
|
|
|
static int inited = 0;
|
|
|
|
void
|
|
usage()
|
|
{
|
|
fprintf(stderr, "Usage: kadmin [-u admin_name] [-r default_realm]");
|
|
#ifndef NO_MULTIPLE
|
|
fprintf(stderr, " [-m]");
|
|
#endif
|
|
fprintf(stderr, "\n");
|
|
#ifndef NO_MULTIPLE
|
|
fprintf(stderr, " -m allows multiple admin requests to be ");
|
|
fprintf(stderr, "serviced with one entry of admin\n");
|
|
fprintf(stderr, " password.\n");
|
|
#endif
|
|
exit(1);
|
|
}
|
|
|
|
static void
|
|
do_init(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
struct passwd *pw;
|
|
extern char *optarg;
|
|
extern int optind;
|
|
int c;
|
|
#ifndef NO_MULTIPLE
|
|
#define OPTION_STRING "u:r:m"
|
|
#else
|
|
#define OPTION_STRING "u:r:"
|
|
#endif
|
|
|
|
bzero(myname, sizeof(myname));
|
|
|
|
if (!inited) {
|
|
/*
|
|
* This is only as a default/initial realm; we don't care
|
|
* about failure.
|
|
*/
|
|
if (krb_get_lrealm(default_realm, 1) != KSUCCESS)
|
|
strcpy(default_realm, KRB_REALM);
|
|
|
|
/*
|
|
* If we can reach the local realm, initialize to it. Otherwise,
|
|
* don't initialize.
|
|
*/
|
|
if (kadm_init_link(PWSERV_NAME, KRB_MASTER, krbrlm) != KADM_SUCCESS)
|
|
bzero(krbrlm, sizeof(krbrlm));
|
|
else
|
|
strcpy(krbrlm, default_realm);
|
|
|
|
while ((c = getopt(argc, argv, OPTION_STRING)) != EOF)
|
|
switch (c) {
|
|
case 'u':
|
|
strncpy(myname, optarg, sizeof(myname) - 1);
|
|
break;
|
|
case 'r':
|
|
bzero(default_realm, sizeof(default_realm));
|
|
strncpy(default_realm, optarg, sizeof(default_realm) - 1);
|
|
break;
|
|
#ifndef NO_MULTIPLE
|
|
case 'm':
|
|
multiple++;
|
|
break;
|
|
#endif
|
|
default:
|
|
usage();
|
|
break;
|
|
}
|
|
if (optind < argc)
|
|
usage();
|
|
if (!myname[0]) {
|
|
pw = getpwuid((int) getuid());
|
|
if (!pw) {
|
|
fprintf(stderr,
|
|
"You aren't in the password file. Who are you?\n");
|
|
exit(1);
|
|
}
|
|
(void) strcpy(myname, pw->pw_name);
|
|
}
|
|
inited = 1;
|
|
}
|
|
}
|
|
|
|
#ifdef NOENCRYPTION
|
|
#define read_long_pw_string placebo_read_pw_string
|
|
#else
|
|
#define read_long_pw_string des_read_pw_string
|
|
#endif
|
|
extern int read_long_pw_string();
|
|
|
|
int
|
|
get_admin_password()
|
|
{
|
|
int status;
|
|
char admin_passwd[MAX_KPW_LEN]; /* Admin's password */
|
|
int ticket_life = 1; /* minimum ticket lifetime */
|
|
#ifndef NO_MULTIPLE
|
|
CREDENTIALS c;
|
|
|
|
if (multiple) {
|
|
/* If admin tickets exist and are valid, just exit. */
|
|
bzero(&c, sizeof(c));
|
|
if (krb_get_cred(PWSERV_NAME, KADM_SINST, krbrlm, &c) == KSUCCESS)
|
|
/*
|
|
* If time is less than lifetime - FUDGE_VALUE after issue date,
|
|
* tickets will probably last long enough for the next
|
|
* transaction.
|
|
*/
|
|
if (time(0) < (c.issue_date + (5 * 60 * c.lifetime) - FUDGE_VALUE))
|
|
return(KADM_SUCCESS);
|
|
ticket_life = DEFAULT_TKT_LIFE;
|
|
}
|
|
#endif
|
|
|
|
if (princ_exists(myname, "admin", krbrlm) != PE_NO) {
|
|
if (read_long_pw_string(admin_passwd, sizeof(admin_passwd)-1,
|
|
"Admin password:", 0)) {
|
|
fprintf(stderr, "Error reading admin password.\n");
|
|
goto bad;
|
|
}
|
|
status = krb_get_pw_in_tkt(myname, "admin", krbrlm, PWSERV_NAME,
|
|
KADM_SINST, ticket_life, admin_passwd);
|
|
bzero(admin_passwd, sizeof(admin_passwd));
|
|
}
|
|
else
|
|
status = KDC_PR_UNKNOWN;
|
|
|
|
switch(status) {
|
|
case GT_PW_OK:
|
|
return(GOOD_PW);
|
|
case KDC_PR_UNKNOWN:
|
|
printf("Principal %s.admin@%s does not exist.\n", myname, krbrlm);
|
|
goto bad;
|
|
case GT_PW_BADPW:
|
|
printf("Incorrect admin password.\n");
|
|
goto bad;
|
|
default:
|
|
com_err("kadmin", status+krb_err_base,
|
|
"while getting password tickets");
|
|
goto bad;
|
|
}
|
|
|
|
bad:
|
|
bzero(admin_passwd, sizeof(admin_passwd));
|
|
(void) dest_tkt();
|
|
return(BAD_PW);
|
|
}
|
|
|
|
void
|
|
clean_up()
|
|
{
|
|
(void) dest_tkt();
|
|
return;
|
|
}
|
|
|
|
void
|
|
quit()
|
|
{
|
|
printf("Cleaning up and exiting.\n");
|
|
clean_up();
|
|
exit(0);
|
|
}
|
|
|
|
int
|
|
princ_exists(name, instance, realm)
|
|
char *name;
|
|
char *instance;
|
|
char *realm;
|
|
{
|
|
int status;
|
|
|
|
status = krb_get_pw_in_tkt(name, instance, realm, "krbtgt", realm, 1, "");
|
|
|
|
if ((status == KSUCCESS) || (status == INTK_BADPW))
|
|
return(PE_YES);
|
|
else if (status == KDC_PR_UNKNOWN)
|
|
return(PE_NO);
|
|
else
|
|
return(PE_UNSURE);
|
|
}
|
|
|
|
int
|
|
get_password(low, high, prompt, byteswap)
|
|
unsigned long *low, *high;
|
|
char *prompt;
|
|
int byteswap;
|
|
{
|
|
char new_passwd[MAX_KPW_LEN]; /* new password */
|
|
des_cblock newkey;
|
|
|
|
do {
|
|
if (read_long_pw_string(new_passwd, sizeof(new_passwd)-1, prompt, 1))
|
|
return(BAD_PW);
|
|
if (strlen(new_passwd) == 0)
|
|
printf("Null passwords are not allowed; try again.\n");
|
|
} while (strlen(new_passwd) == 0);
|
|
|
|
#ifdef NOENCRYPTION
|
|
bzero((char *) newkey, sizeof(newkey));
|
|
#else
|
|
des_string_to_key(new_passwd, &newkey);
|
|
#endif
|
|
bzero(new_passwd, sizeof(new_passwd));
|
|
|
|
bcopy((char *) newkey,(char *)low,4);
|
|
bcopy((char *)(((long *) newkey) + 1), (char *)high,4);
|
|
|
|
bzero((char *) newkey, sizeof(newkey));
|
|
|
|
#ifdef NOENCRYPTION
|
|
*low = 1;
|
|
#endif
|
|
|
|
if (byteswap != DONTSWAP) {
|
|
*low = htonl(*low);
|
|
*high = htonl(*high);
|
|
}
|
|
return(GOOD_PW);
|
|
}
|