kadmin.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright 1994 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. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* 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.
*
* kadmin.c: base functions for a kadmin command line interface using
* the OVSecure library
*/
#include <krb5.h>
#include <k5-int.h>
#include <kadm5/admin.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <math.h>
#include <unistd.h>
#include <pwd.h>
/* #include <sys/timeb.h> */
#include <time.h>
#include <libintl.h>
/*
* Solaris: the following are needed for paging
*/
#include <signal.h>
#include <sys/wait.h>
/* command name when called "locally" (i.e. non-networked client ) */
#define KADMIN_LOCAL_NAME "kadmin.local"
/* functions defined in remote/local specific files */
extern void usage(const char *);
extern void debugEnable(int);
/* local principal helpers */
static char *find_component(const char *, char);
static char *trim_principal(char *);
static char *build_admin_princ(const char *, const char *);
/*
* special struct to convert flag names for principals
* to actual krb5_flags for a principal
*/
struct pflag {
char *flagname; /* name of flag as typed to CLI */
int flaglen; /* length of string (not counting -,+) */
krb5_flags theflag; /* actual principal flag to set/clear */
int set; /* 0 means clear, 1 means set (on '-') */
};
static struct pflag flags[] = {
{"allow_postdated", 15, KRB5_KDB_DISALLOW_POSTDATED, 1},
{"allow_forwardable", 17, KRB5_KDB_DISALLOW_FORWARDABLE, 1},
{"allow_tgs_req", 13, KRB5_KDB_DISALLOW_TGT_BASED, 1},
{"allow_renewable", 15, KRB5_KDB_DISALLOW_RENEWABLE, 1},
{"allow_proxiable", 15, KRB5_KDB_DISALLOW_PROXIABLE, 1},
{"allow_dup_skey", 14, KRB5_KDB_DISALLOW_DUP_SKEY, 1},
{"allow_tix", 9, KRB5_KDB_DISALLOW_ALL_TIX, 1},
{"requires_preauth", 16, KRB5_KDB_REQUIRES_PRE_AUTH, 0},
{"requires_hwauth", 15, KRB5_KDB_REQUIRES_HW_AUTH, 0},
{"needchange", 10, KRB5_KDB_REQUIRES_PWCHANGE, 0},
{"allow_svr", 9, KRB5_KDB_DISALLOW_SVR, 1},
{"password_changing_service", 25, KRB5_KDB_PWCHANGE_SERVICE, 0 },
{"support_desmd5", 14, KRB5_KDB_SUPPORT_DESMD5, 0 }
};
static char *prflags[] = {
"DISALLOW_POSTDATED", /* 0x00000001 */
"DISALLOW_FORWARDABLE", /* 0x00000002 */
"DISALLOW_TGT_BASED", /* 0x00000004 */
"DISALLOW_RENEWABLE", /* 0x00000008 */
"DISALLOW_PROXIABLE", /* 0x00000010 */
"DISALLOW_DUP_SKEY", /* 0x00000020 */
"DISALLOW_ALL_TIX", /* 0x00000040 */
"REQUIRES_PRE_AUTH", /* 0x00000080 */
"REQUIRES_HW_AUTH", /* 0x00000100 */
"REQUIRES_PWCHANGE", /* 0x00000200 */
"UNKNOWN_0x00000400", /* 0x00000400 */
"UNKNOWN_0x00000800", /* 0x00000800 */
"DISALLOW_SVR", /* 0x00001000 */
"PWCHANGE_SERVICE", /* 0x00002000 */
"SUPPORT_DESMD5", /* 0x00004000 */
"NEW_PRINC", /* 0x00008000 */
};
char *getenv();
int exit_status = 0;
char *def_realm = NULL;
char *whoami = NULL;
time_t get_date();
void *handle = NULL;
krb5_context context;
char *ccache_name = NULL;
char *
strdur(duration)
time_t duration;
{
static char out[100];
int days, hours, minutes, seconds;
days = duration / (24 * 3600);
duration %= 24 * 3600;
hours = duration / 3600;
duration %= 3600;
minutes = duration / 60;
duration %= 60;
seconds = duration;
if (days == 1) {
snprintf(out, sizeof (out), gettext("%d day %02d:%02d:%02d"),
days, hours, minutes, seconds);
} else {
snprintf(out, sizeof (out), gettext("%d days %02d:%02d:%02d"),
days, hours, minutes, seconds);
}
return (out);
}
char *
strdate(when)
krb5_timestamp when;
{
struct tm *tm;
static char out[30];
time_t lcltim = when;
tm = localtime(&lcltim);
strftime(out, 30, gettext("%a %b %d %H:%M:%S %Z %Y"), tm);
return (out);
}
/*
* this is a wrapper to go around krb5_parse_principal so we can set
* the default realm up properly
*/
krb5_error_code
kadmin_parse_name(name, principal)
char *name;
krb5_principal *principal;
{
char *cp, *fullname;
krb5_error_code retval;
if (name == NULL)
return (EINVAL);
/* assumes def_realm is initialized! */
fullname = (char *)malloc(strlen(name) + 1 + strlen(def_realm) + 1);
if (fullname == NULL)
return (ENOMEM);
strcpy(fullname, name);
cp = strchr(fullname, '@');
while (cp) {
if (cp - fullname && *(cp - 1) != '\\')
break;
else
cp = strchr((cp + 1), '@');
}
if (cp == NULL) {
strcat(fullname, "@");
strcat(fullname, def_realm);
}
retval = krb5_parse_name(context, fullname, principal);
free(fullname);
return (retval);
}
char *
kadmin_startup(argc, argv)
int argc;
char *argv[];
{
extern krb5_kt_ops krb5_ktf_writable_ops;
extern char *optarg;
char *princstr = NULL, *keytab_name = NULL, *query = NULL;
char *password = NULL;
char *kadmin_princ = NULL;
char *luser, *canon, *cp;
int optchar, use_keytab = 0, debug = 0;
struct passwd *pw;
kadm5_ret_t retval;
krb5_ccache cc;
krb5_principal princ;
kadm5_config_params params;
memset((char *) &params, 0, sizeof(params));
if (retval = krb5_init_context(&context)) {
com_err(whoami, retval,
gettext("while initializing krb5 library"));
exit(1);
}
while ((optchar = getopt(argc, argv, "Dr:p:kq:w:d:s:mc:t:e:O")) != EOF) {
switch (optchar) {
case 'O': /* Undocumented option for testing only */
kadmin_princ = KADM5_ADMIN_SERVICE_P;
break;
case 'D':
debug++;
break;
case 'r':
def_realm = optarg;
break;
case 'p':
princstr = strdup(optarg);
if (princstr == NULL) {
fprintf(stderr, gettext("Out of memory in %s\n"),
whoami);
exit(1);
}
break;
case 'c':
ccache_name = optarg;
break;
case 'k':
use_keytab++;
break;
case 't':
keytab_name = optarg;
break;
case 'w':
password = optarg;
break;
case 'q':
query = optarg;
break;
case 'd':
params.dbname = optarg;
params.mask |= KADM5_CONFIG_DBNAME;
break;
case 's':
params.admin_server = optarg;
params.mask |= KADM5_CONFIG_ADMIN_SERVER;
break;
case 'm':
params.mkey_from_kbd = 1;
params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
break;
case 'e':
retval = krb5_string_to_keysalts(optarg,
", \t", ":.-", 0,
&params.keysalts,
&params.num_keysalts);
if (retval) {
com_err(whoami, retval,
gettext("while parsing keysalts %s"), optarg);
exit(1);
}
params.mask |= KADM5_CONFIG_ENCTYPES;
break;
default:
usage(whoami);
}
}
debugEnable(debug);
if ((ccache_name && use_keytab) ||
(keytab_name && !use_keytab))
usage(whoami);
if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) {
free(princstr);
fprintf(stderr,
gettext("%s: unable to get default realm\n"), whoami);
exit(1);
}
params.mask |= KADM5_CONFIG_REALM;
params.realm = def_realm;
if (kadmin_princ == NULL) {
if (kadm5_get_adm_host_srv_name(context,
def_realm, &kadmin_princ)) {
fprintf(stderr,
gettext("%s: unable to get host based "
"service name for realm %s\n"),
whoami, def_realm);
free(princstr);
exit(1);
}
}
/*
* Set cc to an open credentials cache, either specified by the -c
* argument or the default.
*/
if (ccache_name == NULL) {
if (retval = krb5_cc_default(context, &cc)) {
com_err(whoami, retval,
gettext("while opening default "
"credentials cache"));
exit(1);
}
} else {
if (retval = krb5_cc_resolve(context, ccache_name, &cc)) {
com_err(whoami, retval,
gettext("while opening credentials cache %s"),
ccache_name);
exit(1);
}
}
/*
* If no principal name is specified: If a ccache was specified and
* its primary principal name can be read, it is used, else if a
* keytab was specified, the principal name is host/hostname,
* otherwise append "/admin" to the primary name of the default
* ccache, $USER, or pw_name.
*
* Gee, 100+ lines to figure out the client principal name. This
* should be compressed...
*/
if (princstr == NULL) {
if (ccache_name != NULL &&
!krb5_cc_get_principal(context, cc, &princ)) {
if (retval = krb5_unparse_name(context, princ,
&princstr)) {
com_err(whoami, retval,
gettext("while canonicalizing principal name"));
krb5_free_principal(context, princ);
exit(1);
}
krb5_free_principal(context, princ);
} else if (use_keytab != 0) {
if (retval = krb5_sname_to_principal(context, NULL,
"host", KRB5_NT_SRV_HST,
&princ)) {
com_err(whoami, retval,
gettext("creating host service principal"));
exit(1);
}
if (retval = krb5_unparse_name(context, princ,
&princstr)) {
com_err(whoami, retval,
gettext("while canonicalizing "
"principal name"));
krb5_free_principal(context, princ);
exit(1);
}
krb5_free_principal(context, princ);
} else if (!krb5_cc_get_principal(context, cc, &princ)) {
char *realm = NULL;
if (krb5_unparse_name(context, princ, &canon)) {
fprintf(stderr,
gettext("%s: unable to canonicalize "
"principal\n"), whoami);
krb5_free_principal(context, princ);
exit(1);
}
krb5_free_principal(context, princ);
(void) trim_principal(canon);
princstr = build_admin_princ(canon, def_realm);
free(canon);
} else if (luser = getenv("USER")) {
princstr = build_admin_princ(luser, def_realm);
} else if (pw = getpwuid(getuid())) {
princstr = build_admin_princ(pw->pw_name, def_realm);
} else {
fprintf(stderr,
gettext("%s: unable to figure out "
"a principal name\n"),
whoami);
exit(1);
}
} else { /* (princstr != NULL) */
/* See if we need to add the default realm */
if (find_component(princstr, '@') == NULL) {
size_t len;
/* principal @ realm NULL */
len = strlen(princstr) + 1 + strlen(def_realm) + 1;
princstr = realloc(princstr, len);
if (princstr == NULL) {
fprintf(stderr,
gettext("%s: out of memory\n"), whoami);
exit(1);
}
strcat(princstr, "@");
strcat(princstr, def_realm);
}
}
/*
* Initialize the kadm5 connection. If we were given a ccache, use
* it. Otherwise, use/prompt for the password.
*/
if (ccache_name) {
printf(gettext(
"Authenticating as principal %s with existing credentials.\n"),
princstr);
retval = kadm5_init_with_creds(princstr, cc,
kadmin_princ,
&params,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_2,
&handle);
} else if (use_keytab) {
if (keytab_name)
printf(gettext("Authenticating as principal %s with keytab %s.\n"),
princstr, keytab_name);
else
printf(gettext(
"Authenticating as principal %s with default keytab.\n"),
princstr);
retval = kadm5_init_with_skey(princstr, keytab_name,
kadmin_princ,
&params,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_2,
&handle);
} else {
printf(gettext("Authenticating as principal %s with password.\n"),
princstr);
retval = kadm5_init_with_password(princstr, password,
kadmin_princ, &params,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_2,
&handle);
}
if (retval) {
if (retval == KADM5_RPC_ERROR_CANTENCODEARGS ||
retval == KADM5_RPC_ERROR_CANTDECODEARGS) {
com_err(whoami, KADM5_RPC_ERROR,
gettext("while initializing %s interface"), whoami);
/* privacy-enabled mech probably not installed/configed */
com_err(whoami, retval, gettext("."), whoami);
} else {
com_err(whoami, retval,
gettext("while initializing %s interface"), whoami);
if (retval == KADM5_BAD_CLIENT_PARAMS ||
retval == KADM5_BAD_SERVER_PARAMS)
usage(whoami);
}
exit(1);
}
free(princstr);
if (retval = krb5_cc_close(context, cc)) {
com_err(whoami, retval, gettext("while closing ccache %s"),
ccache_name);
exit(1);
}
/* register the WRFILE keytab type and set it as the default */
if (retval = krb5_kt_register(context, &krb5_ktf_writable_ops)) {
com_err(whoami, retval,
gettext("while registering writable key table functions"));
exit(1);
}
{
/*
* XXX krb5_defkeyname is an internal library global and
* should go away
*/
extern char *krb5_defkeyname;
krb5_defkeyname = DEFAULT_KEYTAB;
}
if ((retval = kadm5_init_iprop(handle)) != 0) {
com_err(whoami, retval, gettext("while mapping update log"));
exit(1);
}
/* Solaris kerberos: fix memory leak */
if (kadmin_princ)
free(kadmin_princ);
return (query);
}
static char *
find_component(const char *principal, char sep)
{
char *p = strchr(principal, sep);
for(p = strchr(principal, sep); p; p = strchr(p, sep))
if (p != principal && *(p - 1) != '\\')
break;
return (p);
}
static char *
trim_principal(char *principal)
{
char *p = find_component(principal, '/');
if (p == NULL)
p = find_component(principal, '@');
if (p)
*p = '\0';
return (principal);
}
static char *
build_admin_princ(const char *user, const char *realm)
{
char *princstr;
/* Add 7 to the length for "/admin@" */
princstr = (char *) malloc(strlen(user) + 7 + strlen(realm) + 1);
if (princstr == NULL) {
fprintf(stderr,
gettext("%s: out of memory\n"),
whoami);
exit(1);
}
sprintf(princstr, "%s/admin@%s", user, realm);
return (princstr);
}
int
quit()
{
krb5_ccache cc;
int retval;
kadm5_destroy(handle);
if (ccache_name != NULL) {
fprintf(stderr,
gettext("\n\a\a\aAdministration credentials "
"NOT DESTROYED.\n"));
}
/* insert more random cleanup here */
krb5_free_context(context);
context = NULL;
return (0);
}
void
kadmin_delprinc(argc, argv)
int argc;
char *argv[];
{
kadm5_ret_t retval;
krb5_principal princ;
char *canon;
char reply[32];
if (! (argc == 2 ||
(argc == 3 && strcmp("-force", argv[1]) == 0))) {
fprintf(stderr, "%s: delete_principal [-force] %s\n",
gettext("usage"), gettext("principal"));
return;
}
retval = kadmin_parse_name(argv[argc - 1], &princ);
if (retval) {
com_err("delete_principal", retval,
gettext("while parsing principal name"));
return;
}
retval = krb5_unparse_name(context, princ, &canon);
if (retval) {
com_err("delete_principal", retval,
gettext("while canonicalizing principal"));
krb5_free_principal(context, princ);
return;
}
if (argc == 2) {
printf(gettext("Are you sure you want to delete "
"the principal \"%s\"? (yes/no): "), canon);
fgets(reply, sizeof (reply), stdin);
if (strncmp(gettext("yes\n"), reply, sizeof (reply)) &&
strncmp(gettext("y\n"), reply, sizeof (reply)) &&
strncmp(gettext("Y\n"), reply, sizeof (reply))) {
fprintf(stderr,
gettext("Principal \"%s\" not deleted\n"),
canon);
free(canon);
krb5_free_principal(context, princ);
return;
}
}
retval = kadm5_delete_principal(handle, princ);
krb5_free_principal(context, princ);
if (retval) {
com_err("delete_principal", retval,
gettext("while deleting principal \"%s\""), canon);
free(canon);
return;
}
printf(gettext("Principal \"%s\" deleted.\n"), canon);
printf(gettext("Make sure that you have removed this principal "
"from all ACLs before reusing.\n"));
free(canon);
}
void
kadmin_cpw(argc, argv)
int argc;
char *argv[];
{
kadm5_ret_t retval;
static char newpw[1024];
static char prompt1[1024], prompt2[1024];
char *canon;
char *pwarg = NULL;
int n_ks_tuple = 0, keepold = 0, randkey = 0;
krb5_key_salt_tuple *ks_tuple = NULL;
krb5_principal princ;
if (argc < 2) {
goto usage;
}
for (argv++, argc--; argc > 1; argc--, argv++) {
if (!strcmp("-pw", *argv)) {
argc--;
if (argc < 1) {
fprintf(stderr, "change_password: %s",
gettext("missing password arg\n"));
goto usage;
}
pwarg = *++argv;
continue;
}
if (!strcmp("-randkey", *argv)) {
randkey++;
continue;
}
if (!strcmp("-keepold", *argv)) {
keepold++;
continue;
}
if (!strcmp("-e", *argv)) {
argc--;
if (argc < 1) {
fprintf(stderr, "change_password: %s",
gettext("missing keysaltlist arg\n"));
goto usage;
}
retval = krb5_string_to_keysalts(*++argv, ", \t", ":.-", 0,
&ks_tuple, &n_ks_tuple);
if (retval) {
com_err("change_password", retval,
gettext("while parsing keysalts %s"), *argv);
return;
}
continue;
}
goto usage;
}
retval = kadmin_parse_name(*argv, &princ);
if (retval) {
com_err("change_password", retval,
gettext("while parsing principal name"));
if (ks_tuple != NULL)
free(ks_tuple);
goto usage;
}
retval = krb5_unparse_name(context, princ, &canon);
if (retval) {
com_err("change_password", retval,
gettext("while canonicalizing principal"));
krb5_free_principal(context, princ);
if (ks_tuple != NULL)
free(ks_tuple);
return;
}
if (pwarg != NULL) {
if (keepold || ks_tuple != NULL) {
retval = kadm5_chpass_principal_3(handle, princ, keepold,
n_ks_tuple, ks_tuple, pwarg);
if (ks_tuple != NULL)
free(ks_tuple);
} else {
retval = kadm5_chpass_principal(handle, princ, pwarg);
}
krb5_free_principal(context, princ);
if (retval) {
com_err("change_password", retval,
gettext("while changing password for \"%s\"."),
canon);
free(canon);
return;
}
printf(gettext("Password for \"%s\" changed.\n"), canon);
free(canon);
return;
} else if (randkey) {
if (keepold || ks_tuple != NULL) {
retval = kadm5_randkey_principal_3(handle, princ, keepold,
n_ks_tuple, ks_tuple,
NULL, NULL);
if (ks_tuple != NULL)
free(ks_tuple);
} else {
retval = kadm5_randkey_principal(handle, princ, NULL, NULL);
}
krb5_free_principal(context, princ);
if (retval) {
com_err("change_password", retval,
gettext("while randomizing key for \"%s\"."),
canon);
free(canon);
return;
}
printf(gettext("Key for \"%s\" randomized.\n"), canon);
free(canon);
return;
} else if (argc == 1) {
unsigned int i = sizeof (newpw) - 1;
snprintf(prompt1, sizeof (prompt1),
gettext("Enter password for principal \"%.900s\": "),
*argv);
snprintf(prompt2, sizeof (prompt2),
gettext("Re-enter password for principal \"%.900s\": "),
*argv);
retval = krb5_read_password(context, prompt1, prompt2,
newpw, &i);
if (retval) {
com_err("change_password", retval,
gettext("while reading password for \"%s\"."),
canon);
free(canon);
if (ks_tuple != NULL)
free(ks_tuple);
krb5_free_principal(context, princ);
return;
}
if (keepold || ks_tuple != NULL) {
retval = kadm5_chpass_principal_3(handle, princ, keepold,
n_ks_tuple, ks_tuple,
newpw);
if (ks_tuple != NULL)
free(ks_tuple);
} else {
retval = kadm5_chpass_principal(handle, princ, newpw);
}
krb5_free_principal(context, princ);
memset(newpw, 0, sizeof (newpw));
if (retval) {
com_err("change_password", retval,
gettext("while changing password for \"%s\"."),
canon);
free(canon);
return;
}
printf(gettext("Password for \"%s\" changed.\n"), canon);
free(canon);
return;
} else {
free(canon);
krb5_free_principal(context, princ);
usage:
fprintf(stderr, "%s: change_password [-randkey] [-keepold] "
"[-e keysaltlist] [-pw password] %s\n",
gettext("usage"), gettext("principal"));
return;
}
}
int kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, randkey,
ks_tuple, n_ks_tuple, caller)
int argc;
char *argv[];
kadm5_principal_ent_t oprinc;
long *mask;
char **pass;
int *randkey;
krb5_key_salt_tuple **ks_tuple;
int *n_ks_tuple;
char *caller;
{
int i, j, attrib_set;
time_t date;
time_t now;
krb5_error_code retval;
*mask = 0;
*pass = NULL;
*n_ks_tuple = 0;
*ks_tuple = NULL;
time(&now);
*randkey = 0;
for (i = 1; i < argc - 1; i++) {
attrib_set = 0;
if (strlen(argv[i]) == 7 &&
strcmp("-expire", argv[i]) == 0) {
if (++i > argc - 2)
return (-1);
else {
date = get_date(argv[i], NULL);
if (date == (time_t)-1) {
fprintf(stderr,
gettext("Invalid date "
"specification "
"\"%s\".\n"),
argv[i]);
return (-1);
}
oprinc->princ_expire_time = date;
*mask |= KADM5_PRINC_EXPIRE_TIME;
continue;
}
}
if (strlen(argv[i]) == 9 &&
strcmp("-pwexpire", argv[i]) == 0) {
if (++i > argc - 2)
return (-1);
else {
date = get_date(argv[i], NULL);
if (date == (time_t)-1) {
fprintf(stderr,
gettext("Invalid date "
"specification "
"\"%s\".\n"),
argv[i]);
return (-1);
}
oprinc->pw_expiration = date;
*mask |= KADM5_PW_EXPIRATION;
continue;
}
}
if (strlen(argv[i]) == 8 &&
strcmp("-maxlife", argv[i]) == 0) {
if (++i > argc - 2)
return (-1);
else {
date = get_date(argv[i], NULL);
if (date == (time_t)-1) {
fprintf(stderr,
gettext("Invalid date "
"specification "
"\"%s\".\n"),
argv[i]);
return (-1);
}
if (date <= now) {
fprintf(stderr,
gettext("Date specified is "
"in the past "
"\"%s\".\n"),
argv[i]);
return (-1);
}
oprinc->max_life = date - now;
*mask |= KADM5_MAX_LIFE;
continue;
}
}
if (strlen(argv[i]) == 13 &&
strcmp("-maxrenewlife", argv[i]) == 0) {
if (++i > argc - 2)
return (-1);
else {
date = get_date(argv[i], NULL);
if (date == (time_t)-1) {
fprintf(stderr,
gettext("Invalid date "
"specification "
"\"%s\".\n"),
argv[i]);
return (-1);
}
if (date <= now) {
fprintf(stderr,
gettext("Date specified is "
"in the past "
"\"%s\".\n"),
argv[i]);
return (-1);
}
oprinc->max_renewable_life = date - now;
*mask |= KADM5_MAX_RLIFE;
continue;
}
}
if (strlen(argv[i]) == 5 &&
strcmp("-kvno", argv[i]) == 0) {
if (++i > argc - 2)
return (-1);
else {
oprinc->kvno = atoi(argv[i]);
*mask |= KADM5_KVNO;
continue;
}
}
if (strlen(argv[i]) == 7 &&
strcmp("-policy", argv[i]) == 0) {
if (++i > argc - 2)
return (-1);
else {
oprinc->policy = argv[i];
*mask |= KADM5_POLICY;
continue;
}
}
if (strlen(argv[i]) == 12 &&
strcmp("-clearpolicy", argv[i]) == 0) {
oprinc->policy = NULL;
*mask |= KADM5_POLICY_CLR;
continue;
}
if (strlen(argv[i]) == 3 &&
strcmp("-pw", argv[i]) == 0) {
if (++i > argc - 2)
return (-1);
else {
*pass = argv[i];
continue;
}
}
if (strlen(argv[i]) == 8 &&
strcmp("-randkey", argv[i]) == 0) {
++*randkey;
continue;
}
if (!strcmp("-e", argv[i])) {
if (++i > argc - 2)
return -1;
else {
retval = krb5_string_to_keysalts(argv[i], ", \t", ":.-", 0,
ks_tuple, n_ks_tuple);
if (retval) {
com_err(caller, retval,
gettext("while parsing keysalts %s"), argv[i]);
return -1;
}
}
continue;
}
for (j = 0; j < sizeof (flags) / sizeof (struct pflag); j++) {
if (strlen(argv[i]) == flags[j].flaglen + 1 &&
strcmp(flags[j].flagname,
/* strip off leading + or - */
&argv[i][1]) == 0) {
if (flags[j].set && argv[i][0] == '-' ||
!flags[j].set && argv[i][0] == '+') {
oprinc->attributes |= flags[j].theflag;
*mask |= KADM5_ATTRIBUTES;
attrib_set++;
break;
} else if (flags[j].set && argv[i][0] == '+' ||
!flags[j].set && argv[i][0] == '-') {
oprinc->attributes &= ~flags[j].theflag;
*mask |= KADM5_ATTRIBUTES;
attrib_set++;
break;
} else {
return (-1);
}
}
}
if (!attrib_set)
return (-1); /* nothing was parsed */
}
if (i != argc - 1) {
return (-1);
}
retval = kadmin_parse_name(argv[i], &oprinc->principal);
if (retval) {
com_err(caller, retval, gettext("while parsing principal"));
return (-1);
}
return (0);
}
void
kadmin_addprinc_usage(func)
char *func;
{
fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
gettext("[options] principal"));
fprintf(stderr, gettext("\toptions are:\n"));
fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] "
"[-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] "
"[-randkey] [-pw password]\n\t\t[-maxrenewlife maxrenewlife] "
"[-e keysaltlist] [{+|-}attribute]\n");
fprintf(stderr, gettext("\tattributes are:\n"));
fprintf(stderr, "%s%s%s",
"\t\tallow_postdated allow_forwardable allow_tgs_req "
"allow_renewable\n",
"\t\tallow_proxiable allow_dup_skey allow_tix "
"requires_preauth\n",
"\t\trequires_hwauth needchange allow_svr "
"password_changing_service\n");
}
void
kadmin_modprinc_usage(func)
char *func;
{
fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
gettext("[options] principal"));
fprintf(stderr, gettext("\toptions are:\n"));
fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] "
"[-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] "
"[-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] "
"[{+|-}attribute]\n");
fprintf(stderr, gettext("\tattributes are:\n"));
fprintf(stderr, "%s%s%s",
"\t\tallow_postdated allow_forwardable allow_tgs_req "
"allow_renewable\n",
"\t\tallow_proxiable allow_dup_skey allow_tix "
"requires_preauth\n",
"\t\trequires_hwauth needchange allow_svr "
"password_changing_service\n");
}
void
kadmin_addprinc(argc, argv)
int argc;
char *argv[];
{
kadm5_principal_ent_rec princ, dprinc;
kadm5_policy_ent_rec defpol;
long mask;
int randkey = 0, i;
int n_ks_tuple;
krb5_key_salt_tuple *ks_tuple;
char *pass, *canon;
krb5_error_code retval;
static char newpw[1024], dummybuf[256];
static char prompt1[1024], prompt2[1024];
int local_kadmin = 0;
local_kadmin = (strcmp(whoami, KADMIN_LOCAL_NAME) == 0);
if (dummybuf[0] == 0) {
for (i = 0; i < 256; i++)
dummybuf[i] = (i+1) % 256;
}
/* Zero all fields in request structure */
memset(&princ, 0, sizeof(princ));
memset(&dprinc, 0, sizeof(dprinc));
princ.attributes = dprinc.attributes = 0;
if (kadmin_parse_princ_args(argc, argv,
&princ, &mask, &pass, &randkey,
&ks_tuple, &n_ks_tuple,
"add_principal")) {
kadmin_addprinc_usage("add_principal");
return;
}
retval = krb5_unparse_name(context, princ.principal, &canon);
if (retval) {
com_err("add_principal", retval,
gettext("while canonicalizing principal"));
krb5_free_principal(context, princ.principal);
if (ks_tuple != NULL)
free(ks_tuple);
return;
}
/*
* If -policy was not specified, and -clearpolicy was not
* specified, and the policy "default" exists, assign it. If
* -clearpolicy was specified, then KADM5_POLICY_CLR should be
* unset, since it is never valid for kadm5_create_principal.
*/
if ((! (mask & KADM5_POLICY)) &&
(! (mask & KADM5_POLICY_CLR))) {
if (! kadm5_get_policy(handle, "default", &defpol)) {
fprintf(stderr,
gettext(
"NOTICE: no policy specified for %s; assigning \"default\"\n"),
canon);
princ.policy = "default";
mask |= KADM5_POLICY;
(void) kadm5_free_policy_ent(handle, &defpol);
} else
fprintf(stderr, gettext("WARNING: no policy specified "
"for %s; defaulting to no policy\n"), canon);
}
mask &= ~KADM5_POLICY_CLR;
/*
* Set 'notix' for randkey principals and also for principals which have
* specified flag options on the cmdline. This is because we want to apply
* generic flag settings from 'default_principal_flags' first (during
* principal creation), followed by a kadm5_modify_principal() which
* correctly applies the cli flag options. So, we do *not* want any tix
* issued in the interim.
*/
if (randkey || (mask & KADM5_ATTRIBUTES))
princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
if (randkey) {
pass = dummybuf;
mask |= KADM5_ATTRIBUTES;
} else if (pass == NULL) {
unsigned int i = sizeof (newpw) - 1;
snprintf(prompt1, sizeof (prompt1),
gettext("Enter password for principal \"%.900s\": "),
canon);
snprintf(prompt2, sizeof (prompt1),
gettext("Re-enter password for principal \"%.900s\": "),
canon);
retval = krb5_read_password(context, prompt1, prompt2,
newpw, &i);
if (retval) {
com_err("add_principal", retval,
gettext("while reading password for \"%s\"."), canon);
free(canon);
krb5_free_principal(context, princ.principal);
return;
}
pass = newpw;
}
mask |= KADM5_PRINCIPAL;
/*
* If the client being used is local, always use the new
* API so we get the full set of enctype support.
*/
if (ks_tuple != NULL || local_kadmin) {
retval = kadm5_create_principal_3(handle, &princ, mask,
n_ks_tuple, ks_tuple, pass);
} else {
retval = kadm5_create_principal(handle, &princ, mask, pass);
}
if (retval) {
com_err("add_principal", retval,
gettext("while creating \"%s\"."), canon);
krb5_free_principal(context, princ.principal);
free(canon);
if (ks_tuple != NULL)
free(ks_tuple);
return;
}
if (randkey) { /* more special stuff for -randkey */
if (ks_tuple != NULL || local_kadmin) {
retval = kadm5_randkey_principal_3(handle, princ.principal,
FALSE,
n_ks_tuple, ks_tuple,
NULL, NULL);
} else {
retval = kadm5_randkey_principal(handle, princ.principal,
NULL, NULL);
}
if (retval) {
com_err("add_principal", retval,
gettext("while randomizing key for \"%s\"."), canon);
krb5_free_principal(context, princ.principal);
free(canon);
if (ks_tuple != NULL)
free(ks_tuple);
return;
}
}
/*
* We now retrieve the intersection set of the generic flag settings and
* the ones specified on the cli & re-parse the princ args, just to make
* sure we account for conflicts between 'default_principal_flags' and
* the cmdline flag args. While we are here, also clear 'notix'.
*/
if (randkey || (mask & KADM5_ATTRIBUTES)) {
retval = kadm5_get_principal(handle, princ.principal, &dprinc,
KADM5_PRINCIPAL_NORMAL_MASK);
if (retval == 0) {
if (dprinc.attributes != 0)
princ.attributes = dprinc.attributes;
} else {
com_err("add_principal", retval,
gettext("while doing a get_principal on \"%s\"."), canon);
printf(gettext("\nWarning: Principal \"%s\" could have incomplete "
"flag settings, as a result of a failed get_principal.\n"
"Check the 'default_principal_flags' setting in kdc.conf(4).\n"
"If there is a mismatch, use modprinc in kadmin(1M) to rectify "
"the same.\n\n"), canon);
}
(void) kadmin_parse_princ_args(argc, argv, &princ, &mask, &pass,
&randkey, &ks_tuple, &n_ks_tuple, "add_principal");
princ.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX;
mask = KADM5_ATTRIBUTES;
retval = kadm5_modify_principal(handle, &princ, mask);
if (retval) {
com_err("add_principal", retval,
gettext("while doing a modify_principal to restore flag "
"settings for \"%s\"."), canon);
krb5_free_principal(context, princ.principal);
free(canon);
if (ks_tuple != NULL)
free(ks_tuple);
return;
}
}
krb5_free_principal(context, princ.principal);
printf(gettext("Principal \"%s\" created.\n"), canon);
if (ks_tuple != NULL)
free(ks_tuple);
free(canon);
}
void
kadmin_modprinc(argc, argv)
int argc;
char *argv[];
{
kadm5_principal_ent_rec princ, oldprinc;
krb5_principal kprinc;
long mask;
krb5_error_code retval;
char *pass, *canon;
int randkey = 0;
int n_ks_tuple = 0;
krb5_key_salt_tuple *ks_tuple;
if (argc < 2) {
kadmin_modprinc_usage("modify_principal");
return;
}
memset(&oldprinc, 0, sizeof(oldprinc));
memset(&princ, 0, sizeof(princ));
retval = kadmin_parse_name(argv[argc - 1], &kprinc);
if (retval) {
com_err("modify_principal", retval,
gettext("while parsing principal"));
return;
}
retval = krb5_unparse_name(context, kprinc, &canon);
if (retval) {
com_err("modify_principal", retval,
gettext("while canonicalizing principal"));
krb5_free_principal(context, kprinc);
return;
}
retval = kadm5_get_principal(handle, kprinc, &oldprinc,
KADM5_PRINCIPAL_NORMAL_MASK);
krb5_free_principal(context, kprinc);
if (retval) {
com_err("modify_principal", retval,
gettext("while getting \"%s\"."), canon);
free(canon);
return;
}
princ.attributes = oldprinc.attributes;
kadm5_free_principal_ent(handle, &oldprinc);
retval = kadmin_parse_princ_args(argc, argv,
&princ, &mask,
&pass, &randkey,
&ks_tuple, &n_ks_tuple,
"modify_principal");
if (ks_tuple != NULL) {
free(ks_tuple);
kadmin_modprinc_usage("modify_principal");
free(canon);
return;
}
if (retval) {
kadmin_modprinc_usage("modify_principal");
free(canon);
return;
}
if (randkey) {
fprintf(stderr, "modify_principal: -randkey %s ",
gettext("not allowed\n"));
krb5_free_principal(context, princ.principal);
free(canon);
return;
}
if (pass) {
fprintf(stderr,
"modify_principal: -pw %s change_password\n",
gettext("not allowed; use"));
krb5_free_principal(context, princ.principal);
free(canon);
return;
}
retval = kadm5_modify_principal(handle, &princ, mask);
krb5_free_principal(context, princ.principal);
if (retval) {
com_err("modify_principal", retval,
gettext("while modifying \"%s\"."), canon);
free(canon);
return;
}
printf(gettext("Principal \"%s\" modified.\n"), canon);
free(canon);
}
void
kadmin_getprinc(argc, argv)
int argc;
char *argv[];
{
kadm5_principal_ent_rec dprinc;
krb5_principal princ;
krb5_error_code retval;
char *canon, *modcanon;
int i;
if (! (argc == 2 ||
(argc == 3 && strcmp("-terse", argv[1]) == 0))) {
fprintf(stderr, "%s: get_principal [-terse] %s\n",
gettext("usage"), gettext("principal"));
return;
}
memset(&dprinc, 0, sizeof(dprinc));
memset(&princ, 0, sizeof(princ));
retval = kadmin_parse_name(argv[argc - 1], &princ);
if (retval) {
com_err("get_principal", retval,
gettext("while parsing principal"));
return;
}
retval = krb5_unparse_name(context, princ, &canon);
if (retval) {
com_err("get_principal", retval,
gettext("while canonicalizing principal"));
krb5_free_principal(context, princ);
return;
}
retval = kadm5_get_principal(handle, princ, &dprinc,
KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA);
krb5_free_principal(context, princ);
if (retval) {
com_err("get_principal", retval,
gettext("while retrieving \"%s\"."), canon);
free(canon);
return;
}
retval = krb5_unparse_name(context, dprinc.mod_name, &modcanon);
if (retval) {
com_err("get_principal", retval,
gettext("while unparsing modname"));
kadm5_free_principal_ent(handle, &dprinc);
free(canon);
return;
}
if (argc == 2) {
printf(gettext("Principal: %s\n"), canon);
printf(gettext("Expiration date: %s\n"),
dprinc.princ_expire_time ?
strdate(dprinc.princ_expire_time) :
gettext("[never]"));
printf(gettext("Last password change: %s\n"),
dprinc.last_pwd_change ?
strdate(dprinc.last_pwd_change) :
gettext("[never]"));
printf(gettext("Password expiration date: %s\n"),
dprinc.pw_expiration ?
strdate(dprinc.pw_expiration) : gettext("[none]"));
printf(gettext("Maximum ticket life: %s\n"),
strdur(dprinc.max_life));
printf(gettext("Maximum renewable life: %s\n"),
strdur(dprinc.max_renewable_life));
printf(gettext("Last modified: %s (%s)\n"),
strdate(dprinc.mod_date), modcanon);
printf(gettext("Last successful authentication: %s\n"),
dprinc.last_success ? strdate(dprinc.last_success) :
gettext("[never]"));
printf(gettext("Last failed authentication: %s\n"),
dprinc.last_failed ? strdate(dprinc.last_failed) :
gettext("[never]"));
printf(gettext("Failed password attempts: %d\n"),
dprinc.fail_auth_count);
printf(gettext("Number of keys: %d\n"), dprinc.n_key_data);
for (i = 0; i < dprinc.n_key_data; i++) {
krb5_key_data *key_data = &dprinc.key_data[i];
char enctype[BUFSIZ], salttype[BUFSIZ];
if (krb5_enctype_to_string(key_data->key_data_type[0],
enctype, sizeof(enctype)))
snprintf(enctype, sizeof (enctype),
gettext("<Encryption type 0x%x>"),
key_data->key_data_type[0]);
printf(gettext("Key: vno %d, %s, "),
key_data->key_data_kvno, enctype);
if (key_data->key_data_ver > 1) {
if (krb5_salttype_to_string(
key_data->key_data_type[1],
salttype, sizeof(salttype)))
snprintf(salttype, sizeof (salttype),
gettext("<Salt type 0x%x>"),
key_data->key_data_type[1]);
printf("%s\n", salttype);
} else
printf(gettext("no salt\n"));
}
printf(gettext("Attributes:"));
for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
if (dprinc.attributes & (krb5_flags) 1 << i)
printf(" %s", prflags[i]);
}
printf("\n");
printf(gettext("Policy: %s\n"),
dprinc.policy ? dprinc.policy : gettext("[none]"));
} else {
printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\""
"\t%d\t%d\t%d\t%d\t%d",
canon, dprinc.princ_expire_time, dprinc.last_pwd_change,
dprinc.pw_expiration, dprinc.max_life, modcanon,
dprinc.mod_date, dprinc.attributes, dprinc.kvno,
dprinc.mkvno, dprinc.policy ?
dprinc.policy : gettext("[none]"),
dprinc.max_renewable_life, dprinc.last_success,
dprinc.last_failed, dprinc.fail_auth_count,
dprinc.n_key_data);
for (i = 0; i < dprinc.n_key_data; i++)
printf("\t%d\t%d\t%d\t%d",
dprinc.key_data[i].key_data_ver,
dprinc.key_data[i].key_data_kvno,
dprinc.key_data[i].key_data_type[0],
dprinc.key_data[i].key_data_type[1]);
printf("\n");
}
free(modcanon);
kadm5_free_principal_ent(handle, &dprinc);
free(canon);
}
void
kadmin_getprincs(argc, argv)
int argc;
char *argv[];
{
krb5_error_code retval;
char *exp, **names;
int i, count;
FILE *output;
int fd;
struct sigaction nsig, osig;
sigset_t nmask, omask;
int waitb;
exp = NULL;
if (! (argc == 1 || (argc == 2 && (exp = argv[1])))) {
fprintf(stderr, "%s: get_principals %s\n",
gettext("usage"), gettext("[expression]"));
return;
}
retval = kadm5_get_principals(handle, exp, &names, &count);
if (retval) {
com_err("get_principals", retval,
gettext("while retrieving list."));
return;
}
/*
* Solaris: the following code is used for paging
*/
sigemptyset(&nmask);
sigaddset(&nmask, SIGINT);
sigprocmask(SIG_BLOCK, &nmask, &omask);
nsig.sa_handler = SIG_IGN;
sigemptyset(&nsig.sa_mask);
nsig.sa_flags = 0;
sigaction(SIGINT, &nsig, &osig);
fd = ss_pager_create();
output = fdopen(fd, "w");
sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
for (i = 0; i < count; i++)
fprintf(output, "%s\n", names[i]);
fclose(output);
wait(&waitb);
kadm5_free_name_list(handle, names, count);
}
int
kadmin_parse_policy_args(argc, argv, policy, mask, caller)
int argc;
char *argv[];
kadm5_policy_ent_t policy;
long *mask;
char *caller;
{
int i;
time_t now;
time_t date;
krb5_error_code retval;
time(&now);
*mask = 0;
for (i = 1; i < argc - 1; i++) {
if (strlen(argv[i]) == 8 &&
strcmp(argv[i], "-maxlife") == 0) {
if (++i > argc -2)
return (-1);
else {
date = get_date(argv[i], NULL);
if (date == (time_t)-1) {
fprintf(stderr,
gettext("Invalid date "
"specification "
"\"%s\".\n"),
argv[i]);
return (-1);
}
if (date <= now) {
fprintf(stderr,
gettext("Date specified is "
"in the past "
"\"%s\".\n"),
argv[i]);
return (-1);
}
policy->pw_max_life = date - now;
*mask |= KADM5_PW_MAX_LIFE;
continue;
}
} else if (strlen(argv[i]) == 8 &&
strcmp(argv[i], "-minlife") == 0) {
if (++i > argc - 2)
return (-1);
else {
date = get_date(argv[i], NULL);
if (date == (time_t)-1) {
fprintf(stderr,
gettext("Invalid date "
"specification "
"\"%s\".\n"),
argv[i]);
return (-1);
}
if (date <= now) {
fprintf(stderr,
gettext("Date specified is "
"in the past "
"\"%s\".\n"),
argv[i]);
return (-1);
}
policy->pw_min_life = date - now;
*mask |= KADM5_PW_MIN_LIFE;
continue;
}
} else if (strlen(argv[i]) == 10 &&
strcmp(argv[i], "-minlength") == 0) {
if (++i > argc - 2)
return (-1);
else {
policy->pw_min_length = atoi(argv[i]);
*mask |= KADM5_PW_MIN_LENGTH;
continue;
}
} else if (strlen(argv[i]) == 11 &&
strcmp(argv[i], "-minclasses") == 0) {
if (++i > argc - 2)
return (-1);
else {
policy->pw_min_classes = atoi(argv[i]);
*mask |= KADM5_PW_MIN_CLASSES;
continue;
}
} else if (strlen(argv[i]) == 8 &&
strcmp(argv[i], "-history") == 0) {
if (++i > argc - 2)
return (-1);
else {
policy->pw_history_num = atoi(argv[i]);
*mask |= KADM5_PW_HISTORY_NUM;
continue;
}
} else
return (-1);
}
if (i != argc -1) {
fprintf(stderr, gettext("%s: parser lost count!\n"), caller);
return (-1);
} else
return (0);
}
void
kadmin_addmodpol_usage(func)
char *func;
{
fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
gettext("[options] policy"));
fprintf(stderr, gettext("\toptions are:\n"));
fprintf(stderr, "\t\t[-maxlife time] [-minlife time] "
"[-minlength length]\n\t\t[-minclasses number] "
"[-history number]\n");
}
void
kadmin_addpol(argc, argv)
int argc;
char *argv[];
{
krb5_error_code retval;
long mask;
kadm5_policy_ent_rec policy;
memset(&policy, 0, sizeof(policy));
if (kadmin_parse_policy_args(argc, argv,
&policy, &mask, "add_policy")) {
kadmin_addmodpol_usage("add_policy");
return;
} else {
policy.policy = argv[argc - 1];
mask |= KADM5_POLICY;
retval = kadm5_create_policy(handle, &policy, mask);
if (retval) {
com_err("add_policy", retval,
gettext("while creating policy \"%s\"."),
policy.policy);
return;
}
}
}
void
kadmin_modpol(argc, argv)
int argc;
char *argv[];
{
krb5_error_code retval;
long mask;
kadm5_policy_ent_rec policy;
memset(&policy, 0, sizeof(policy));
if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
"modify_policy")) {
kadmin_addmodpol_usage("modify_policy");
return;
} else {
policy.policy = argv[argc - 1];
retval = kadm5_modify_policy(handle, &policy, mask);
if (retval) {
com_err("modify_policy", retval,
gettext("while modifying policy \"%s\"."),
policy.policy);
return;
}
}
}
void
kadmin_delpol(argc, argv)
int argc;
char *argv[];
{
krb5_error_code retval;
char reply[32];
if (! (argc == 2 ||
(argc == 3 && strcmp("-force", argv[1]) == 0))) {
fprintf(stderr, "%s: delete_policy [-force] %s\n",
gettext("usage"), gettext("policy"));
return;
}
if (argc == 2) {
printf(gettext("Are you sure you want to delete the policy "
"\"%s\"? (yes/no): "), argv[1]);
fgets(reply, sizeof (reply), stdin);
if (strncmp(gettext("yes\n"), reply, sizeof (reply)) &&
strncmp(gettext("y\n"), reply, sizeof (reply)) &&
strncmp(gettext("Y\n"), reply, sizeof (reply))
) {
fprintf(stderr,
gettext("Policy \"%s\" not deleted.\n"),
argv[1]);
return;
}
}
retval = kadm5_delete_policy(handle, argv[argc - 1]);
if (retval) {
com_err("delete_policy:", retval,
gettext("while deleting policy \"%s\""),
argv[argc - 1]);
return;
}
}
void
kadmin_getpol(argc, argv)
int argc;
char *argv[];
{
krb5_error_code retval;
kadm5_policy_ent_rec policy;
if (! (argc == 2 ||
(argc == 3 && strcmp("-terse", argv[1]) == 0))) {
fprintf(stderr, "%s: get_policy [-terse] %s\n",
gettext("usage"), gettext("policy"));
return;
}
retval = kadm5_get_policy(handle, argv[argc - 1], &policy);
if (retval) {
com_err("get_policy", retval,
gettext("while retrieving policy \"%s\"."),
argv[argc - 1]);
return;
}
if (argc == 2) {
printf(gettext("Policy: %s\n"), policy.policy);
printf(gettext("Maximum password life: %d\n"),
policy.pw_max_life);
printf(gettext("Minimum password life: %d\n"),
policy.pw_min_life);
printf(gettext("Minimum password length: %d\n"),
policy.pw_min_length);
printf(gettext("Minimum number of password "
"character classes: %d\n"),
policy.pw_min_classes);
printf(gettext("Number of old keys kept: %d\n"),
policy.pw_history_num);
printf(gettext("Reference count: %d\n"), policy.policy_refcnt);
} else {
printf("\"%s\"\t%d\t%d\t%d\t%d\t%d\t%d\n",
policy.policy, policy.pw_max_life, policy.pw_min_life,
policy.pw_min_length, policy.pw_min_classes,
policy.pw_history_num, policy.policy_refcnt);
}
kadm5_free_policy_ent(handle, &policy);
}
void
kadmin_getpols(argc, argv)
int argc;
char *argv[];
{
krb5_error_code retval;
char *exp, **names;
int i, count;
exp = NULL;
if (! (argc == 1 || (argc == 2 && (exp = argv[1])))) {
fprintf(stderr, "%s: get_policies %s\n",
gettext("usage"), gettext("[expression]\n"));
return;
}
retval = kadm5_get_policies(handle, exp, &names, &count);
if (retval) {
com_err("get_policies", retval,
gettext("while retrieving list."));
return;
}
for (i = 0; i < count; i++)
printf("%s\n", names[i]);
kadm5_free_name_list(handle, names, count);
}