summaryrefslogtreecommitdiffstats
path: root/src/kadmin
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2009-10-25 16:55:12 +0000
committerGreg Hudson <ghudson@mit.edu>2009-10-25 16:55:12 +0000
commit8d31a9d396f5bea88def4db395ad12dca2ac2e9f (patch)
tree244f8f5b525432a2a2a280403f38d7b2fbdc0dfd /src/kadmin
parentb82e46df9b6cbf663512985a99c6d79f2b0cb796 (diff)
downloadkrb5-8d31a9d396f5bea88def4db395ad12dca2ac2e9f.tar.gz
krb5-8d31a9d396f5bea88def4db395ad12dca2ac2e9f.tar.xz
krb5-8d31a9d396f5bea88def4db395ad12dca2ac2e9f.zip
Account lockout
Merge Luke's users/lhoward/lockout2 branch to trunk. Implements account lockout policies for preauth-using principals using existing principal metadata fields and new policy fields. The kadmin API version is bumped from 2 to 3 to compatibly extend the policy_ent_rec structure. ticket: 6577 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23038 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kadmin')
-rw-r--r--src/kadmin/cli/kadmin.c55
-rw-r--r--src/kadmin/dbutil/dump.c285
-rw-r--r--src/kadmin/dbutil/kadm5_create.c2
-rw-r--r--src/kadmin/dbutil/kdb5_util.M9
-rw-r--r--src/kadmin/dbutil/kdb5_util.c4
-rw-r--r--src/kadmin/server/ipropd_svc.c37
-rw-r--r--src/kadmin/server/ovsec_kadmd.c2
-rw-r--r--src/kadmin/server/server_stubs.c4
-rwxr-xr-xsrc/kadmin/testing/scripts/init_db10
-rwxr-xr-xsrc/kadmin/testing/scripts/start_servers_local2
-rw-r--r--src/kadmin/testing/tcl/util.t2
-rw-r--r--src/kadmin/testing/util/tcl_kadm5.c47
12 files changed, 375 insertions, 84 deletions
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
index ad9f6bc9bd..51746def44 100644
--- a/src/kadmin/cli/kadmin.c
+++ b/src/kadmin/cli/kadmin.c
@@ -486,7 +486,7 @@ kadmin_startup(int argc, char *argv[])
princstr);
retval = kadm5_init_with_creds(context, princstr, cc, svcname, &params,
KADM5_STRUCT_VERSION,
- KADM5_API_VERSION_2, db_args, &handle);
+ KADM5_API_VERSION_3, db_args, &handle);
} else if (use_keytab) {
if (keytab_name)
printf("Authenticating as principal %s with keytab %s.\n",
@@ -496,13 +496,13 @@ kadmin_startup(int argc, char *argv[])
princstr);
retval = kadm5_init_with_skey(context, princstr, keytab_name, svcname,
&params, KADM5_STRUCT_VERSION,
- KADM5_API_VERSION_2, db_args, &handle);
+ KADM5_API_VERSION_3, db_args, &handle);
} else {
printf("Authenticating as principal %s with password.\n",
princstr);
retval = kadm5_init_with_password(context, princstr, password, svcname,
&params, KADM5_STRUCT_VERSION,
- KADM5_API_VERSION_2, db_args,
+ KADM5_API_VERSION_3, db_args,
&handle);
}
if (retval) {
@@ -970,6 +970,11 @@ kadmin_parse_princ_args(int argc, char *argv[], kadm5_principal_ent_t oprinc,
}
}
#endif /* APPLE_PKINIT */
+ if (strlen(argv[i]) == 7 && !strcmp("-unlock", argv[i])) {
+ oprinc->fail_auth_count = 0;
+ *mask |= KADM5_FAIL_AUTH_COUNT;
+ continue;
+ }
if (!strcmp("-e", argv[i])) {
if (++i > argc - 2)
return -1;
@@ -1047,7 +1052,7 @@ kadmin_modprinc_usage()
{
fprintf(stderr, "usage: modify_principal [options] principal\n");
fprintf(stderr, "\toptions are:\n");
- fprintf(stderr, "\t\t[-x db_princ_args]* [-expire expdate] [-pwexpire pwexpdate] [-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] [-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] [{+|-}attribute]\n");
+ fprintf(stderr, "\t\t[-x db_princ_args]* [-expire expdate] [-pwexpire pwexpdate] [-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] [-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] [-unlock] [{+|-}attribute]\n");
fprintf(stderr, "\tattributes are:\n");
fprintf(stderr, "%s%s%s",
"\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
@@ -1496,6 +1501,33 @@ kadmin_parse_policy_args(int argc, char *argv[], kadm5_policy_ent_t policy,
*mask |= KADM5_PW_HISTORY_NUM;
continue;
}
+ } else if (strlen(argv[i]) == 11 &&
+ !strcmp(argv[i], "-maxfailure")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_max_fail = atoi(argv[i]);
+ *mask |= KADM5_PW_MAX_FAILURE;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 21 &&
+ !strcmp(argv[i], "-failurecountinterval")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_failcnt_interval = atoi(argv[i]);
+ *mask |= KADM5_PW_FAILURE_COUNT_INTERVAL;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 16 &&
+ !strcmp(argv[i], "-lockoutduration")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_lockout_duration = atoi(argv[i]);
+ *mask |= KADM5_PW_LOCKOUT_DURATION;
+ continue;
+ }
} else
return -1;
}
@@ -1511,7 +1543,8 @@ kadmin_addmodpol_usage(char *func)
{
fprintf(stderr, "usage; %s [options] policy\n", func);
fprintf(stderr, "\toptions are:\n");
- fprintf(stderr, "\t\t[-maxlife time] [-minlife time] [-minlength length]\n\t\t[-minclasses number] [-history number]\n");
+ fprintf(stderr, "\t\t[-maxlife time] [-minlife time] [-minlength length]\n\t\t[-minclasses number] [-history number]\n\t\t[-maxfailure number] [-failurecountinterval time]\n");
+ fprintf(stderr, "\t\t[-lockoutduration time]\n");
}
void
@@ -1607,11 +1640,19 @@ kadmin_getpol(int argc, char *argv[])
policy.pw_min_classes);
printf("Number of old keys kept: %ld\n", policy.pw_history_num);
printf("Reference count: %ld\n", policy.policy_refcnt);
+ printf("Maximum password failures before lockout: %ld\n",
+ policy.pw_max_fail);
+ printf("Password failure count reset interval: %ld\n",
+ (long)policy.pw_failcnt_interval);
+ printf("Password lockout duration: %ld\n",
+ (long)policy.pw_lockout_duration);
} else {
- printf("\"%s\"\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\n",
+ printf("\"%s\"\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\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);
+ policy.pw_history_num, policy.policy_refcnt,
+ policy.pw_max_fail, (long)policy.pw_failcnt_interval,
+ (long)policy.pw_lockout_duration);
}
kadm5_free_policy_ent(handle, &policy);
}
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index 8dab4605ce..c03e88d123 100644
--- a/src/kadmin/dbutil/dump.c
+++ b/src/kadmin/dbutil/dump.c
@@ -66,13 +66,17 @@ static int recursive;
#include <regexp.h>
#endif /* !HAVE_REGCOMP && HAVE_REGEXP_H */
+#define FLAG_VERBOSE 0x1 /* be verbose */
+#define FLAG_UPDATE 0x2 /* processing an update */
+#define FLAG_OMIT_NRA 0x4 /* avoid dumping non-replicated attrs */
+
struct dump_args {
char *programname;
FILE *ofile;
krb5_context kcontext;
char **names;
int nnames;
- int verbose;
+ int flags;
};
static krb5_error_code dump_k5beta_iterator (krb5_pointer,
@@ -92,6 +96,7 @@ static krb5_error_code dump_k5beta7_princ_withpolicy
static krb5_error_code dump_ov_princ (krb5_pointer,
krb5_db_entry *);
static void dump_k5beta7_policy (void *, osa_policy_ent_t);
+static void dump_r1_8_policy (void *, osa_policy_ent_t);
typedef krb5_error_code (*dump_func)(krb5_pointer,
krb5_db_entry *);
@@ -102,6 +107,8 @@ static int process_k5beta6_record (char *, krb5_context,
FILE *, int, int *);
static int process_k5beta7_record (char *, krb5_context,
FILE *, int, int *);
+static int process_r1_8_record (char *, krb5_context,
+ FILE *, int, int *);
static int process_ov_record (char *, krb5_context,
FILE *, int, int *);
typedef krb5_error_code (*load_func)(char *, krb5_context,
@@ -172,6 +179,24 @@ dump_version r1_3_version = {
dump_k5beta7_policy,
process_k5beta7_record,
};
+dump_version r1_8_version = {
+ "Kerberos version 5 release 1.8",
+ "kdb5_util load_dump version 6\n",
+ 0,
+ 0,
+ dump_k5beta7_princ_withpolicy,
+ dump_r1_8_policy,
+ process_r1_8_record,
+};
+dump_version ipropx_1_version = {
+ "Kerberos iprop extensible version",
+ "ipropx",
+ 0,
+ 0,
+ dump_k5beta7_princ_withpolicy,
+ dump_r1_8_policy,
+ process_r1_8_record,
+};
/* External data */
extern char *current_dbname;
@@ -197,6 +222,7 @@ static const char null_mprinc_name[] = "kdb5_dump@MISSING";
#define stand_fmt_name "Kerberos version 5"
#define old_fmt_name "Kerberos version 5 old format"
#define b6_fmt_name "Kerberos version 5 beta 6 format"
+#define r1_3_fmt_name "Kerberos version 5 release 1.3 format"
#define ofopen_error "%s: cannot open %s for writing (%s)\n"
#define oflock_error "%s: cannot lock %s (%s)\n"
#define dumprec_err "%s: error performing %s dump (%s)\n"
@@ -257,6 +283,7 @@ static const char verboseoption[] = "-verbose";
static const char updateoption[] = "-update";
static const char hashoption[] = "-hash";
static const char ovoption[] = "-ov";
+static const char r13option[] = "-r13";
static const char dump_tmptrail[] = "~";
/*
@@ -646,8 +673,11 @@ dump_k5beta_iterator(ptr, entry)
(krb5_int32) pkey->key_data_kvno,
entry->max_life, entry->max_renewable_life,
1 /* Fake mkvno */, entry->expiration, entry->pw_expiration,
- last_pwd_change, entry->last_success, entry->last_failed,
- entry->fail_auth_count, mod_name, mod_date,
+ last_pwd_change,
+ (arg->flags & FLAG_OMIT_NRA) ? 0 : entry->last_success,
+ (arg->flags & FLAG_OMIT_NRA) ? 0 : entry->last_failed,
+ (arg->flags & FLAG_OMIT_NRA) ? 0 : entry->fail_auth_count,
+ mod_name, mod_date,
entry->attributes, pkey->key_data_type[1]);
/* Pound out the salt data, if present. */
@@ -670,7 +700,7 @@ dump_k5beta_iterator(ptr, entry)
}
fprintf(arg->ofile, ";\n");
/* If we're blabbing, do it */
- if (arg->verbose)
+ if (arg->flags & FLAG_VERBOSE)
fprintf(stderr, "%s\n", name);
free(mod_name);
}
@@ -790,9 +820,9 @@ dump_k5beta6_iterator_ext(ptr, entry, kadm)
entry->max_renewable_life,
entry->expiration,
entry->pw_expiration,
- entry->last_success,
- entry->last_failed,
- entry->fail_auth_count);
+ (arg->flags & FLAG_OMIT_NRA) ? 0 : entry->last_success,
+ (arg->flags & FLAG_OMIT_NRA) ? 0 : entry->last_failed,
+ (arg->flags & FLAG_OMIT_NRA) ? 0 : entry->fail_auth_count);
/* Pound out tagged data. */
for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
if (tlp->tl_data_type == KRB5_TL_KADM_DATA && !kadm)
@@ -839,7 +869,7 @@ dump_k5beta6_iterator_ext(ptr, entry, kadm)
/* Print trailer */
fprintf(arg->ofile, ";\n");
- if (arg->verbose)
+ if (arg->flags & FLAG_VERBOSE)
fprintf(stderr, "%s\n", name);
}
else {
@@ -926,6 +956,19 @@ void dump_k5beta7_policy(void *data, osa_policy_ent_t entry)
entry->policy_refcnt);
}
+void dump_r1_8_policy(void *data, osa_policy_ent_t entry)
+{
+ struct dump_args *arg;
+
+ arg = (struct dump_args *) data;
+ fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
+ entry->name,
+ entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
+ entry->pw_min_classes, entry->pw_history_num,
+ entry->policy_refcnt, entry->pw_max_fail,
+ entry->pw_failcnt_interval, entry->pw_lockout_duration);
+}
+
static void print_key_data(FILE *f, krb5_key_data *key_data)
{
int c;
@@ -963,7 +1006,8 @@ static void print_key_data(FILE *f, krb5_key_data *key_data)
static krb5_error_code dump_ov_princ(krb5_pointer ptr, krb5_db_entry *kdb)
{
char *princstr;
- int x, y, foundcrc;
+ unsigned int x;
+ int y, foundcrc;
struct dump_args *arg;
krb5_tl_data tl_data;
osa_princ_ent_rec adb;
@@ -986,7 +1030,7 @@ static krb5_error_code dump_ov_princ(krb5_pointer ptr, krb5_db_entry *kdb)
return 0;
memset(&adb, 0, sizeof(adb));
- xdrmem_create(&xdrs, tl_data.tl_data_contents,
+ xdrmem_create(&xdrs, (caddr_t)tl_data.tl_data_contents,
tl_data.tl_data_length, XDR_DECODE);
if (! xdr_osa_princ_ent_rec(&xdrs, &adb)) {
xdr_destroy(&xdrs);
@@ -1034,7 +1078,7 @@ static krb5_error_code dump_ov_princ(krb5_pointer ptr, krb5_db_entry *kdb)
/*
* usage is:
- * dump_db [-old] [-b6] [-b7] [-ov] [-verbose] [-mkey_convert]
+ * dump_db [-old] [-b6] [-b7] [-ov] [-r13] [-verbose] [-mkey_convert]
* [-new_mkey_file mkey_file] [-rev] [-recurse]
* [filename [principals...]]
*/
@@ -1054,13 +1098,14 @@ dump_db(argc, argv)
bool_t dump_sno = FALSE;
kdb_log_context *log_ctx;
char **db_args = 0; /* XXX */
+ unsigned int ipropx_version = IPROPX_VERSION_0;
/*
* Parse the arguments.
*/
ofile = (char *) NULL;
- dump = &r1_3_version;
- arglist.verbose = 0;
+ dump = &r1_8_version;
+ arglist.flags = 0;
new_mkey_file = 0;
mkey_convert = 0;
backwards = 0;
@@ -1079,9 +1124,13 @@ dump_db(argc, argv)
dump = &beta7_version;
else if (!strcmp(argv[aindex], ovoption))
dump = &ov_version;
- else if (!strcmp(argv[aindex], ipropoption)) {
+ else if (!strcmp(argv[aindex], r13option))
+ dump = &r1_3_version;
+ else if (!strncmp(argv[aindex], ipropoption, sizeof(ipropoption) - 1)) {
if (log_ctx && log_ctx->iproprole) {
- dump = &iprop_version;
+ /* Note: ipropx_version is the maximum version acceptable */
+ ipropx_version = atoi(argv[aindex] + sizeof(ipropoption) - 1);
+ dump = ipropx_version ? &ipropx_1_version : &iprop_version;
/*
* dump_sno is used to indicate if the serial
* # should be populated in the output
@@ -1089,13 +1138,18 @@ dump_db(argc, argv)
* the slave's update log when loading
*/
dump_sno = TRUE;
+ /*
+ * FLAG_OMIT_NRA is set to indicate that non-replicated
+ * attributes should be omitted.
+ */
+ arglist.flags |= FLAG_OMIT_NRA;
} else {
fprintf(stderr, _("Iprop not enabled\n"));
exit_status++;
return;
}
} else if (!strcmp(argv[aindex], verboseoption))
- arglist.verbose++;
+ arglist.flags |= FLAG_VERBOSE;
else if (!strcmp(argv[aindex], "-mkey_convert"))
mkey_convert = 1;
else if (!strcmp(argv[aindex], "-new_mkey_file")) {
@@ -1263,6 +1317,8 @@ dump_db(argc, argv)
goto unlock_and_return;
}
+ if (ipropx_version)
+ fprintf(f, " %u", IPROPX_VERSION);
fprintf(f, " %u", log_ctx->ulog->kdb_last_sno);
fprintf(f, " %u", log_ctx->ulog->kdb_last_time.seconds);
fprintf(f, " %u", log_ctx->ulog->kdb_last_time.useconds);
@@ -1467,11 +1523,11 @@ update_tl_data(kcontext, dbentp, mod_name, mod_date, last_pwd_change)
* Returns -1 for end of file, 0 for success and 1 for failure.
*/
static int
-process_k5beta_record(fname, kcontext, filep, verbose, linenop)
+process_k5beta_record(fname, kcontext, filep, flags, linenop)
char *fname;
krb5_context kcontext;
FILE *filep;
- int verbose;
+ int flags;
int *linenop;
{
int nmatched;
@@ -1723,7 +1779,7 @@ process_k5beta_record(fname, kcontext, filep, verbose, linenop)
error++;
}
else {
- if (verbose)
+ if (flags & FLAG_VERBOSE)
fprintf(stderr, add_princ_fmt, name);
retval = 0;
}
@@ -1773,11 +1829,11 @@ process_k5beta_record(fname, kcontext, filep, verbose, linenop)
* Returns -1 for end of file, 0 for success and 1 for failure.
*/
static int
-process_k5beta6_record(fname, kcontext, filep, verbose, linenop)
+process_k5beta6_record(fname, kcontext, filep, flags, linenop)
char *fname;
krb5_context kcontext;
FILE *filep;
- int verbose;
+ int flags;
int *linenop;
{
int retval;
@@ -2024,7 +2080,7 @@ process_k5beta6_record(fname, kcontext, filep, verbose, linenop)
name, error_message(kret));
}
else {
- if (verbose)
+ if (flags & FLAG_VERBOSE)
fprintf(stderr, add_princ_fmt, name);
retval = 0;
}
@@ -2061,17 +2117,19 @@ process_k5beta6_record(fname, kcontext, filep, verbose, linenop)
}
static int
-process_k5beta7_policy(fname, kcontext, filep, verbose, linenop)
+process_k5beta7_policy(fname, kcontext, filep, flags, linenop)
char *fname;
krb5_context kcontext;
FILE *filep;
- int verbose;
+ int flags;
int *linenop;
{
osa_policy_ent_rec rec;
char namebuf[1024];
int nread, ret;
+ memset(&rec, 0, sizeof(rec));
+
(*linenop)++;
rec.name = namebuf;
@@ -2095,23 +2153,73 @@ process_k5beta7_policy(fname, kcontext, filep, verbose, linenop)
return 1;
}
}
- if (verbose)
+ if (flags & FLAG_VERBOSE)
fprintf(stderr, "created policy %s\n", rec.name);
return 0;
}
+static int
+process_r1_8_policy(fname, kcontext, filep, flags, linenop)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int flags;
+ int *linenop;
+{
+ osa_policy_ent_rec rec;
+ char namebuf[1024];
+ int nread, ret;
+
+ memset(&rec, 0, sizeof(rec));
+
+ (*linenop)++;
+ rec.name = namebuf;
+
+ /*
+ * To make this compatible with future policy extensions, we
+ * ignore any additional values.
+ */
+ nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d",
+ rec.name,
+ &rec.pw_min_life, &rec.pw_max_life,
+ &rec.pw_min_length, &rec.pw_min_classes,
+ &rec.pw_history_num, &rec.policy_refcnt,
+ &rec.pw_max_fail, &rec.pw_failcnt_interval,
+ &rec.pw_lockout_duration);
+ if (nread == EOF)
+ return -1;
+ else if (nread < 10) {
+ fprintf(stderr, "cannot parse policy on line %d (%d read)\n",
+ *linenop, nread);
+ return 1;
+ }
+
+ if ((ret = krb5_db_create_policy(kcontext, &rec))) {
+ if (ret &&
+ ((ret = krb5_db_put_policy(kcontext, &rec)))) {
+ fprintf(stderr, "cannot create policy on line %d: %s\n",
+ *linenop, error_message(ret));
+ return 1;
+ }
+ }
+ if (flags & FLAG_VERBOSE)
+ fprintf(stderr, "created policy %s\n", rec.name);
+
+ return 0;
+}
+
/*
* process_k5beta7_record() - Handle a dump record in krb5b7 format.
*
* Returns -1 for end of file, 0 for success and 1 for failure.
*/
static int
-process_k5beta7_record(fname, kcontext, filep, verbose, linenop)
+process_k5beta7_record(fname, kcontext, filep, flags, linenop)
char *fname;
krb5_context kcontext;
FILE *filep;
- int verbose;
+ int flags;
int *linenop;
{
int nread;
@@ -2123,10 +2231,10 @@ process_k5beta7_record(fname, kcontext, filep, verbose, linenop)
else if (nread != 1)
return 1;
if (strcmp(rectype, "princ") == 0)
- process_k5beta6_record(fname, kcontext, filep, verbose,
+ process_k5beta6_record(fname, kcontext, filep, flags,
linenop);
else if (strcmp(rectype, "policy") == 0)
- process_k5beta7_policy(fname, kcontext, filep, verbose,
+ process_k5beta7_policy(fname, kcontext, filep, flags,
linenop);
else {
fprintf(stderr, "unknown record type \"%s\" on line %d\n",
@@ -2143,11 +2251,11 @@ process_k5beta7_record(fname, kcontext, filep, verbose, linenop)
* Returns -1 for end of file, 0 for success and 1 for failure.
*/
static int
-process_ov_record(fname, kcontext, filep, verbose, linenop)
+process_ov_record(fname, kcontext, filep, flags, linenop)
char *fname;
krb5_context kcontext;
FILE *filep;
- int verbose;
+ int flags;
int *linenop;
{
int nread;
@@ -2159,10 +2267,10 @@ process_ov_record(fname, kcontext, filep, verbose, linenop)
else if (nread != 1)
return 1;
if (strcmp(rectype, "princ") == 0)
- process_ov_principal(fname, kcontext, filep, verbose,
+ process_ov_principal(fname, kcontext, filep, flags,
linenop);
else if (strcmp(rectype, "policy") == 0)
- process_k5beta7_policy(fname, kcontext, filep, verbose,
+ process_k5beta7_policy(fname, kcontext, filep, flags,
linenop);
else if (strcmp(rectype, "End") == 0)
return -1;
@@ -2176,15 +2284,51 @@ process_ov_record(fname, kcontext, filep, verbose, linenop)
}
/*
+ * process_r1_8_record() - Handle a dump record in krb5 1.8 format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_r1_8_record(fname, kcontext, filep, flags, linenop)
+ char *fname;
+ krb5_context kcontext;
+ FILE *filep;
+ int flags;
+ int *linenop;
+{
+ int nread;
+ char rectype[100];
+
+ nread = fscanf(filep, "%100s\t", rectype);
+ if (nread == EOF)
+ return -1;
+ else if (nread != 1)
+ return 1;
+ if (strcmp(rectype, "princ") == 0)
+ process_k5beta6_record(fname, kcontext, filep, flags,
+ linenop);
+ else if (strcmp(rectype, "policy") == 0)
+ process_r1_8_policy(fname, kcontext, filep, flags,
+ linenop);
+ else {
+ fprintf(stderr, "unknown record type \"%s\" on line %d\n",
+ rectype, *linenop);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
* restore_dump() - Restore the database from any version dump file.
*/
static int
-restore_dump(programname, kcontext, dumpfile, f, verbose, dump)
+restore_dump(programname, kcontext, dumpfile, f, flags, dump)
char *programname;
krb5_context kcontext;
char *dumpfile;
FILE *f;
- int verbose;
+ int flags;
dump_version *dump;
{
int error;
@@ -2199,7 +2343,7 @@ restore_dump(programname, kcontext, dumpfile, f, verbose, dump)
while (!(error = (*dump->load_record)(dumpfile,
kcontext,
f,
- verbose,
+ flags,
&lineno)))
;
if (error != -1)
@@ -2211,8 +2355,8 @@ restore_dump(programname, kcontext, dumpfile, f, verbose, dump)
}
/*
- * Usage: load_db [-old] [-ov] [-b6] [-b7] [-verbose] [-update] [-hash]
- * filename
+ * Usage: load_db [-old] [-ov] [-b6] [-b7] [-r13] [-verbose]
+ * [-update] [-hash] filename
*/
void
load_db(argc, argv)
@@ -2230,13 +2374,13 @@ load_db(argc, argv)
char *dbname_tmp;
char buf[BUFSIZ];
dump_version *load;
- int update, verbose;
+ int flags;
krb5_int32 crflags;
int aindex;
int db_locked = 0;
char iheader[MAX_HEADER];
kdb_log_context *log_ctx;
- int add_update = 1;
+ krb5_boolean add_update = TRUE;
uint32_t caller, last_sno, last_seconds, last_useconds;
/*
@@ -2245,8 +2389,7 @@ load_db(argc, argv)
dumpfile = (char *) NULL;
dbname = global_params.dbname;
load = NULL;
- update = 0;
- verbose = 0;
+ flags = 0;
crflags = KRB5_KDB_CREATE_BTREE;
exit_status = 0;
dbname_tmp = (char *) NULL;
@@ -2261,6 +2404,8 @@ load_db(argc, argv)
load = &beta7_version;
else if (!strcmp(argv[aindex], ovoption))
load = &ov_version;
+ else if (!strcmp(argv[aindex], r13option))
+ load = &r1_3_version;
else if (!strcmp(argv[aindex], ipropoption)) {
if (log_ctx && log_ctx->iproprole) {
load = &iprop_version;
@@ -2271,9 +2416,9 @@ load_db(argc, argv)
return;
}
} else if (!strcmp(argv[aindex], verboseoption))
- verbose = 1;
+ flags |= FLAG_VERBOSE;
else if (!strcmp(argv[aindex], updateoption))
- update = 1;
+ flags |= FLAG_UPDATE;
else if (!strcmp(argv[aindex], hashoption)) {
if (!add_db_arg("hash=true")) {
com_err(progname, ENOMEM, "while parsing command arguments\n");
@@ -2342,6 +2487,7 @@ load_db(argc, argv)
fgets(buf, sizeof(buf), f);
if (load) {
/* only check what we know; some headers only contain a prefix */
+ /* NB: this should work for ipropx even though load is iprop */
if (strncmp(buf, load->header, strlen(load->header)) != 0) {
fprintf(stderr, head_bad_fmt, progname, dumpfile);
exit_status++;
@@ -2358,6 +2504,8 @@ load_db(argc, argv)
load = &beta7_version;
else if (strcmp(buf, r1_3_version.header) == 0)
load = &r1_3_version;
+ else if (strcmp(buf, r1_8_version.header) == 0)
+ load = &r1_8_version;
else if (strncmp(buf, ov_version.header,
strlen(ov_version.header)) == 0)
load = &ov_version;
@@ -2368,7 +2516,7 @@ load_db(argc, argv)
return;
}
}
- if (load->updateonly && !update) {
+ if (load->updateonly && !(flags & FLAG_UPDATE)) {
fprintf(stderr, "%s: dump version %s can only be loaded with the "
"-update flag\n", progname, load->name);
exit_status++;
@@ -2381,7 +2529,7 @@ load_db(argc, argv)
* be the live db.
*/
newparams = global_params;
- if (! update) {
+ if (! (flags & FLAG_UPDATE)) {
newparams.mask |= KADM5_CONFIG_DBNAME;
newparams.dbname = dbname_tmp;
@@ -2397,12 +2545,17 @@ load_db(argc, argv)
com_err(progname, ENOMEM, "computing parameters for database");
exit(1);
}
+
+ if (!add_update && !add_db_arg("merge_nra")) {
+ com_err(progname, ENOMEM, "computing parameters for database");
+ exit(1);
+ }
}
/*
* If not an update restoration, create the database. otherwise open
*/
- if (!update) {
+ if (!(flags & FLAG_UPDATE)) {
if((kret = krb5_db_create(kcontext, db5util_db_args))) {
const char *emsg = krb5_get_error_message(kcontext, kret);
/*
@@ -2452,7 +2605,10 @@ load_db(argc, argv)
* If an update restoration, make sure the db is left unusable if
* the update fails.
*/
- if ((kret = krb5_db_lock(kcontext, update?KRB5_DB_LOCKMODE_PERMANENT: KRB5_DB_LOCKMODE_EXCLUSIVE))) {
+ if ((kret = krb5_db_lock(kcontext,
+ (flags & FLAG_UPDATE) ?
+ KRB5_DB_LOCKMODE_PERMANENT :
+ KRB5_DB_LOCKMODE_EXCLUSIVE))) {
/*
* Ignore a not supported error since there is nothing to do about it
* anyway.
@@ -2491,7 +2647,7 @@ load_db(argc, argv)
* we could implicity delete db entries during a replace
* no advantage in incr updates when entire db is replaced
*/
- if (!update) {
+ if (!(flags & FLAG_UPDATE)) {
memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t));
log_ctx->ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
@@ -2502,9 +2658,30 @@ load_db(argc, argv)
log_ctx->iproprole = IPROP_NULL;
if (!add_update) {
- sscanf(buf, "%s %u %u %u", iheader, &last_sno,
+ unsigned int ipropx_version = IPROPX_VERSION_0;
+
+ if (!strncmp(buf, "ipropx ", sizeof("ipropx ") - 1))
+ sscanf(buf, "%s %u %u %u %u", iheader,
+ &ipropx_version, &last_sno,
+ &last_seconds, &last_useconds);
+ else
+ sscanf(buf, "%s %u %u %u", iheader, &last_sno,
&last_seconds, &last_useconds);
+ switch (ipropx_version) {
+ case IPROPX_VERSION_0:
+ load = &iprop_version;
+ break;
+ case IPROPX_VERSION_1:
+ load = &ipropx_1_version;
+ break;
+ default:
+ fprintf(stderr, _("%s: Unknown iprop dump version %d\n"),
+ progname, ipropx_version);
+ exit_status++;
+ goto error;
+ }
+
log_ctx->ulog->kdb_last_sno = last_sno;
log_ctx->ulog->kdb_last_time.seconds =
last_seconds;
@@ -2515,13 +2692,13 @@ load_db(argc, argv)
}
if (restore_dump(progname, kcontext, (dumpfile) ? dumpfile : stdin_name,
- f, verbose, load)) {
+ f, flags, load)) {
fprintf(stderr, restfail_fmt,
progname, load->name);
exit_status++;
}
- if (!update && load->create_kadm5 &&
+ if (!(flags & FLAG_UPDATE) && load->create_kadm5 &&
((kret = kadm5_create_magic_princs(&newparams, kcontext)))) {
/* error message printed by create_magic_princs */
exit_status++;
@@ -2544,7 +2721,7 @@ load_db(argc, argv)
/* close policy db below */
- if (exit_status == 0 && !update) {
+ if (exit_status == 0 && !(flags & FLAG_UPDATE)) {
kret = krb5_db_promote(kcontext, db5util_db_args);
/*
* Ignore a not supported error since there is nothing to do about it
@@ -2564,7 +2741,7 @@ error:
*
* If an update: if there was no error, unlock the database.
*/
- if (!update) {
+ if (!(flags & FLAG_UPDATE)) {
if (exit_status) {
kret = krb5_db_destroy(kcontext, db5util_db_args);
/*
diff --git a/src/kadmin/dbutil/kadm5_create.c b/src/kadmin/dbutil/kadm5_create.c
index c2196e54b4..a232babd16 100644
--- a/src/kadmin/dbutil/kadm5_create.c
+++ b/src/kadmin/dbutil/kadm5_create.c
@@ -108,7 +108,7 @@ int kadm5_create_magic_princs(kadm5_config_params *params,
return retval;
if ((retval = kadm5_init(context, progname, NULL, NULL, params,
KADM5_STRUCT_VERSION,
- KADM5_API_VERSION_2,
+ KADM5_API_VERSION_3,
db5util_db_args,
&handle))) {
com_err(progname, retval, "while initializing the Kerberos admin interface");
diff --git a/src/kadmin/dbutil/kdb5_util.M b/src/kadmin/dbutil/kdb5_util.M
index f566781ebd..33ab01aa18 100644
--- a/src/kadmin/dbutil/kdb5_util.M
+++ b/src/kadmin/dbutil/kdb5_util.M
@@ -99,14 +99,14 @@ Stores the master principal's keys in a stash file. The
.B \-f
argument can be used to override the keyfile specified at startup.
.TP
-\fBdump\fP [\fB\-old\fP] [\fB\-b6\fP] [\fB\-b7\fP] [\fB\-ov\fP]
+\fBdump\fP [\fB\-old\fP|\fB-b6\fP|\fB-b7\fP|\fB-ov\fP|\fB-r13\fP]
[\fB\-verbose\fP] [\fB\-mkey_convert\fP]
[\fB\-new_mkey_file\fP \fImkey_file\fP] [\fB\-rev\fP] [\fB\-recurse\fP]
[\fIfilename\fP [\fIprincipals...\fP]]
.br
Dumps the current Kerberos and KADM5 database into an ASCII file. By
default, the database is dumped in current format, "kdb5_util
-load_dumpversion 5". If
+load_dump version 6". If
.I filename
is not specified, or is the string "\-", the dump is sent to standard
output. Options:
@@ -128,6 +128,9 @@ causes the dump to be in
.I ovsec_adm_export
format.
.TP
+.B \-r13
+causes the dump to be in the Kerberos 5 1.3 format ("kdb5_util load_dump version 5"). This was the dump format produced on releases prior to 1.8.
+.TP
.B \-verbose
causes the name of each principal and policy to be printed as it is
dumped.
@@ -154,7 +157,7 @@ option will probably retrieve more principals than the \fB\-rev\fP
option will.
.RE
.TP
-\fBload\fP [\fB\-old\fP] [\fB\-b6\fP] [\fB\-b7\fP] [\fB\-ov\fP] [\fB\-hash\fP]
+\fBload\fP \fB\-old\fP|\fB-b6\fP|\fB-b7\fP|\fB-ov\fP|\fB-r13\fP] [\fB\-hash\fP]
[\fB\-verbose\fP] [\fB\-update\fP] \fIfilename dbname\fP
.br
Loads a database dump from the named file into the named database.
diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c
index 1b0d5a492e..a4b2e686d0 100644
--- a/src/kadmin/dbutil/kdb5_util.c
+++ b/src/kadmin/dbutil/kdb5_util.c
@@ -90,10 +90,10 @@ void usage()
"\tcreate [-s]\n"
"\tdestroy [-f]\n"
"\tstash [-f keyfile]\n"
- "\tdump [-old] [-ov] [-b6] [-verbose]\n"
+ "\tdump [-old|-ov|-b6|-b7|-r13] [-verbose]\n"
"\t [-mkey_convert] [-new_mkey_file mkey_file]\n"
"\t [-rev] [-recurse] [filename [princs...]]\n"
- "\tload [-old] [-ov] [-b6] [-verbose] [-update] filename\n"
+ "\tload [-old|-ov|-b6|-b7|-r13] [-verbose] [-update] filename\n"
"\tark [-e etype_list] principal\n"
"\tadd_mkey [-e etype] [-s]\n"
"\tuse_mkey kvno [time]\n"
diff --git a/src/kadmin/server/ipropd_svc.c b/src/kadmin/server/ipropd_svc.c
index 9140bbdc4c..127a5045d2 100644
--- a/src/kadmin/server/ipropd_svc.c
+++ b/src/kadmin/server/ipropd_svc.c
@@ -241,8 +241,8 @@ getclhoststr(char *clprinc, char *cl, size_t len)
return (NULL);
}
-kdb_fullresync_result_t *
-iprop_full_resync_1_svc(/* LINTED */ void *argp, struct svc_req *rqstp)
+static kdb_fullresync_result_t *
+ipropx_resync(uint32_t vers, struct svc_req *rqstp)
{
static kdb_fullresync_result_t ret;
char *tmpf = 0;
@@ -255,6 +255,13 @@ iprop_full_resync_1_svc(/* LINTED */ void *argp, struct svc_req *rqstp)
char *client_name = NULL, *service_name = NULL;
char *whoami = "iprop_full_resync_1";
+ /*
+ * vers contains the highest version number the client is
+ * willing to accept. A client can always accept a lower
+ * version: the version number is indicated in the dump
+ * header.
+ */
+
/* default return code */
ret.ret = UPDATE_ERROR;
@@ -323,10 +330,12 @@ iprop_full_resync_1_svc(/* LINTED */ void *argp, struct svc_req *rqstp)
/*
* note the -i; modified version of kdb5_util dump format
- * to include sno (serial number)
+ * to include sno (serial number). This argument is now
+ * versioned (-i0 for legacy dump format, -i1 for ipropx
+ * version 1 format, etc)
*/
- if (asprintf(&ubuf, "%s dump -i %s </dev/null 2>&1",
- KPROPD_DEFAULT_KDB5_UTIL, tmpf) < 0) {
+ if (asprintf(&ubuf, "%s dump -i%d %s </dev/null 2>&1",
+ KPROPD_DEFAULT_KDB5_UTIL, vers, tmpf) < 0) {
krb5_klog_syslog(LOG_ERR,
_("%s: cannot construct kdb5 util dump string too long; out of memory"),
whoami);
@@ -422,6 +431,18 @@ out:
return (&ret);
}
+kdb_fullresync_result_t *
+iprop_full_resync_1_svc(/* LINTED */ void *argp, struct svc_req *rqstp)
+{
+ return ipropx_resync(IPROPX_VERSION_0, rqstp);
+}
+
+kdb_fullresync_result_t *
+iprop_full_resync_ext_1_svc(uint32_t *argp, struct svc_req *rqstp)
+{
+ return ipropx_resync(*argp, rqstp);
+}
+
static int
check_iprop_rpcsec_auth(struct svc_req *rqstp)
{
@@ -535,6 +556,12 @@ krb5_iprop_prog_1(struct svc_req *rqstp,
local = (char *(*)()) iprop_full_resync_1_svc;
break;
+ case IPROP_FULL_RESYNC_EXT:
+ _xdr_argument = xdr_u_int32;
+ _xdr_result = xdr_kdb_fullresync_result_t;
+ local = (char *(*)()) iprop_full_resync_ext_1_svc;
+ break;
+
default:
krb5_klog_syslog(LOG_ERR,
_("RPC unknown request: %d (%s)"),
diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c
index fb42c7bde2..c01cbef73a 100644
--- a/src/kadmin/server/ovsec_kadmd.c
+++ b/src/kadmin/server/ovsec_kadmd.c
@@ -306,7 +306,7 @@ int main(int argc, char *argv[])
if((ret = kadm5_init(context, "kadmind", NULL,
NULL, &params,
KADM5_STRUCT_VERSION,
- KADM5_API_VERSION_2,
+ KADM5_API_VERSION_3,
db_args,
&global_server_handle)) != KADM5_OK) {
const char *e_txt = krb5_get_error_message (context, ret);
diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c
index dc949ff18b..9449fe8c22 100644
--- a/src/kadmin/server/server_stubs.c
+++ b/src/kadmin/server/server_stubs.c
@@ -1598,12 +1598,14 @@ generic_ret *init_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp)
trunc_name(&slen, &sdots);
/* okay to cast lengths to int because trunc_name limits max value */
krb5_klog_syslog(LOG_NOTICE, "Request: kadm5_init, %.*s%s, %s, "
- "client=%.*s%s, service=%.*s%s, addr=%s, flavor=%d",
+ "client=%.*s%s, service=%.*s%s, addr=%s, "
+ "vers=%d, flavor=%d",
(int)clen, (char *)client_name.value, cdots,
errmsg ? errmsg : "success",
(int)clen, (char *)client_name.value, cdots,
(int)slen, (char *)service_name.value, sdots,
inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr),
+ ret.api_version & ~(KADM5_API_VERSION_MASK),
rqstp->rq_cred.oa_flavor);
if (errmsg != NULL)
krb5_free_error_message(NULL, errmsg);
diff --git a/src/kadmin/testing/scripts/init_db b/src/kadmin/testing/scripts/init_db
index 1cb96f843c..d5930223da 100755
--- a/src/kadmin/testing/scripts/init_db
+++ b/src/kadmin/testing/scripts/init_db
@@ -103,13 +103,13 @@ if {[info exists env(USER)]} {
set cmds {
{kadm5_init $env(SRVTCL) mrroot null \
[config_params {KADM5_CONFIG_REALM} $r] $KADM5_STRUCT_VERSION \
- $KADM5_API_VERSION_2 server_handle}
+ $KADM5_API_VERSION_3 server_handle}
- {kadm5_create_policy $server_handle "test-pol 0 10000 8 2 3 0" \
- {KADM5_POLICY KADM5_PW_MIN_LENGTH KADM5_PW_MIN_CLASSES KADM5_PW_MAX_LIFE KADM5_PW_HISTORY_NUM}}
- {kadm5_create_policy $server_handle "once-a-min 10 0 0 0 0 0" \
+ {kadm5_create_policy $server_handle "test-pol 0 10000 8 2 3 0 2 90 180" \
+ {KADM5_POLICY KADM5_PW_MIN_LENGTH KADM5_PW_MIN_CLASSES KADM5_PW_MAX_LIFE KADM5_PW_HISTORY_NUM KADM5_PW_MAX_FAILURE KADM5_PW_FAILURE_COUNT_INTERVAL KADM5_PW_LOCKOUT_DURATION}}
+ {kadm5_create_policy $server_handle "once-a-min 10 0 0 0 0 0 0 0 0" \
{KADM5_POLICY KADM5_PW_MIN_LIFE}}
- {kadm5_create_policy $server_handle "dict-only 0 0 0 0 0 0" \
+ {kadm5_create_policy $server_handle "dict-only 0 0 0 0 0 0 0 0 0" \
{KADM5_POLICY}}
{kadm5_create_policy $server_handle [simple_policy test-pol-nopw] \
{KADM5_POLICY}}
diff --git a/src/kadmin/testing/scripts/start_servers_local b/src/kadmin/testing/scripts/start_servers_local
index 8cd0f3a61d..a8890d7318 100755
--- a/src/kadmin/testing/scripts/start_servers_local
+++ b/src/kadmin/testing/scripts/start_servers_local
@@ -83,7 +83,7 @@ if { [catch {
set q $env(QUALNAME)
puts stdout [kadm5_init $env(SRVTCL) mrroot null \
[config_params {KADM5_CONFIG_REALM} $r] \
- $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle]
+ $KADM5_STRUCT_VERSION $KADM5_API_VERSION_3 server_handle]
puts stdout [kadm5_create_principal $server_handle \
[simple_principal host/$q@$r] {KADM5_PRINCIPAL} notathena]
puts stdout [kadm5_destroy $server_handle]
diff --git a/src/kadmin/testing/tcl/util.t b/src/kadmin/testing/tcl/util.t
index 0e39061f77..7721609902 100644
--- a/src/kadmin/testing/tcl/util.t
+++ b/src/kadmin/testing/tcl/util.t
@@ -7,7 +7,7 @@ proc princ_w_pol {name policy} {
}
proc simple_policy {name} {
- return "{$name} 0 0 0 0 0 0"
+ return "{$name} 0 0 0 0 0 0 0 0 0"
}
proc config_params {masks values} {
diff --git a/src/kadmin/testing/util/tcl_kadm5.c b/src/kadmin/testing/util/tcl_kadm5.c
index 6679ce0a7c..08f3a52a4d 100644
--- a/src/kadmin/testing/util/tcl_kadm5.c
+++ b/src/kadmin/testing/util/tcl_kadm5.c
@@ -71,7 +71,10 @@ static struct flagval policy_mask_flags[] = {
{"KADM5_PW_MIN_LENGTH", KADM5_PW_MIN_LENGTH},
{"KADM5_PW_MIN_CLASSES", KADM5_PW_MIN_CLASSES},
{"KADM5_PW_HISTORY_NUM", KADM5_PW_HISTORY_NUM},
- {"KADM5_REF_COUNT", KADM5_REF_COUNT}
+ {"KADM5_REF_COUNT", KADM5_REF_COUNT},
+ {"KADM5_PW_MAX_FAILURE", KADM5_PW_MAX_FAILURE},
+ {"KADM5_PW_FAILURE_COUNT_INTERVAL", KADM5_PW_FAILURE_COUNT_INTERVAL},
+ {"KADM5_PW_LOCKOUT_DURATION", KADM5_PW_LOCKOUT_DURATION},
};
static struct flagval config_mask_flags[] = {
@@ -1309,6 +1312,7 @@ static int parse_principal_ent(Tcl_Interp *interp, char *list,
retcode = TCL_ERROR;
goto finished;
}
+ princ->n_tl_data = tmp;
finished:
Tcl_Free((char *) argv);
@@ -1360,6 +1364,15 @@ static Tcl_DString *unparse_policy_ent(kadm5_policy_ent_t policy)
sprintf(buf, "%ld", policy->policy_refcnt);
Tcl_DStringAppendElement(str, buf);
+ sprintf(buf, "%d", policy->pw_max_fail);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_failcnt_interval);
+ Tcl_DStringAppendElement(str, buf);
+
+ sprintf(buf, "%d", policy->pw_lockout_duration);
+ Tcl_DStringAppendElement(str, buf);
+
return str;
}
@@ -1379,8 +1392,8 @@ static int parse_policy_ent(Tcl_Interp *interp, char *list,
return tcl_ret;
}
- if (argc != 7) {
- sprintf(interp->result, "wrong # args in policy structure (%d should be 7)",
+ if (argc != 7 && argc != 10) {
+ sprintf(interp->result, "wrong # args in policy structure (%d should be 7 or 10)",
argc);
retcode = TCL_ERROR;
goto finished;
@@ -1459,6 +1472,32 @@ static int parse_policy_ent(Tcl_Interp *interp, char *list,
}
policy->policy_refcnt = tmp;
+ if (argc == 7) goto finished;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[7], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_max_fail");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_max_fail = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[8], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_failcnt_interval");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_failcnt_interval = tmp;
+
+ if ((tcl_ret = Tcl_GetInt(interp, argv[9], &tmp))
+ != TCL_OK) {
+ Tcl_AppendElement(interp, "while parsing pw_lockout_duration");
+ retcode = TCL_ERROR;
+ goto finished;
+ }
+ policy->pw_lockout_duration = tmp;
+
finished:
Tcl_Free((char *) argv);
*out_policy = policy;
@@ -2488,6 +2527,8 @@ void Tcl_kadm5_init(Tcl_Interp *interp)
Tcl_SetVar(interp, "KADM5_STRUCT_VERSION", buf, TCL_GLOBAL_ONLY);
(void) sprintf(buf, "%d", KADM5_API_VERSION_2);
Tcl_SetVar(interp, "KADM5_API_VERSION_2", buf, TCL_GLOBAL_ONLY);
+ (void) sprintf(buf, "%d", KADM5_API_VERSION_3);
+ Tcl_SetVar(interp, "KADM5_API_VERSION_3", buf, TCL_GLOBAL_ONLY);
(void) sprintf(buf, "%d", KADM5_API_VERSION_MASK);
Tcl_SetVar(interp, "KADM5_API_VERSION_MASK", buf, TCL_GLOBAL_ONLY);
(void) sprintf(buf, "%d", KADM5_STRUCT_VERSION_MASK);