#include "k5-int.h"
#include "kdb.h"
#include "com_err.h"
#include <ss/ss.h>
#include <stdio.h>
#define REALM_SEP '@'
#define REALM_SEP_STR "@"
struct mblock {
krb5_deltat max_life;
krb5_deltat max_rlife;
krb5_timestamp expiration;
krb5_flags flags;
krb5_kvno mkvno;
} mblock = {
KRB5_KDB_MAX_LIFE,
KRB5_KDB_MAX_RLIFE,
KRB5_KDB_EXPIRATION,
KRB5_KDB_DEF_FLAGS,
1
};
int set_dbname_help (char *, char *);
static void
usage(who, status)
char *who;
int status;
{
fprintf(stderr,
"usage: %s -p prefix -n num_to_create [-d dbpathname] [-r realmname]\n",
who);
fprintf(stderr, "\t [-D depth] [-k enctype] [-M mkeyname]\n");
exit(status);
}
int master_princ_set = 0;
krb5_keyblock master_keyblock;
krb5_principal master_princ;
krb5_db_entry master_entry;
krb5_pointer master_random;
krb5_context test_context;
static char *progname;
static char *cur_realm = 0;
static char *mkey_name = 0;
static char *mkey_password = 0;
static krb5_boolean manual_mkey = FALSE;
void add_princ (krb5_context, char *);
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
int optchar, i, n;
char tmp[4096], tmp2[BUFSIZ], *str_newprinc;
krb5_error_code retval;
char *dbname = 0;
int enctypedone = 0;
int num_to_create;
char principal_string[BUFSIZ];
char *suffix = 0;
int depth;
krb5_init_context(&test_context);
if (strrchr(argv[0], '/'))
argv[0] = strrchr(argv[0], '/')+1;
progname = argv[0];
memset(principal_string, 0, sizeof(principal_string));
num_to_create = 0;
depth = 1;
while ((optchar = getopt(argc, argv, "D:P:p:n:d:r:k:M:e:m")) != -1) {
switch(optchar) {
case 'D':
depth = atoi(optarg);
break;
case 'P':
mkey_password = optarg;
break;
case 'p':
strncpy(principal_string, optarg, sizeof(principal_string) - 1);
principal_string[sizeof(principal_string) - 1] = '\0';
suffix = principal_string + strlen(principal_string);
break;
case 'n':
num_to_create = atoi(optarg);
break;
case 'd':
dbname = optarg;
break;
case 'r':
cur_realm = optarg;
break;
case 'k':
master_keyblock.enctype = atoi(optarg);
enctypedone++;
break;
case 'M':
mkey_name = optarg;
break;
case 'm':
manual_mkey = TRUE;
break;
case '?':
default:
usage(progname, 1);
}
}
if (!(num_to_create && suffix)) usage(progname, 1);
if (!enctypedone)
master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
if (!krb5_c_valid_enctype(master_keyblock.enctype)) {
com_err(progname, KRB5_PROG_ETYPE_NOSUPP,
"while setting up enctype %d", master_keyblock.enctype);
exit(1);
}
if (!dbname)
dbname = DEFAULT_KDB_FILE;
if (!cur_realm) {
if ((retval = krb5_get_default_realm(test_context, &cur_realm))) {
com_err(progname, retval, "while retrieving default realm name");
exit(1);
}
}
if ((retval = set_dbname_help(progname, dbname)))
exit(retval);
for (n = 1; n <= num_to_create; n++) {
(void) sprintf(suffix, "%d", n);
(void) sprintf(tmp, "%s-DEPTH-1", principal_string);
tmp[sizeof(tmp) - 1] = '\0';
str_newprinc = tmp;
add_princ(test_context, str_newprinc);
for (i = 2; i <= depth; i++) {
(void) sprintf(tmp2, "/%s-DEPTH-%d", principal_string, i);
tmp2[sizeof(tmp2) - 1] = '\0';
strncat(tmp, tmp2, sizeof(tmp) - 1 - strlen(tmp));
str_newprinc = tmp;
add_princ(test_context, str_newprinc);
}
}
retval = krb5_db_fini(test_context);
memset((char *)master_keyblock.contents, 0,
(size_t) master_keyblock.length);
if (retval && retval != KRB5_KDB_DBNOTINITED) {
com_err(progname, retval, "while closing database");
exit(1);
}
if (master_princ_set) {
krb5_free_principal(test_context, master_princ);
}
krb5_free_context(test_context);
exit(0);
}
void
add_princ(context, str_newprinc)
krb5_context context;
char * str_newprinc;
{
krb5_error_code retval;
krb5_principal newprinc;
krb5_db_entry newentry;
char princ_name[4096];
memset((char *)&newentry, 0, sizeof(newentry));
sprintf(princ_name, "%s@%s", str_newprinc, cur_realm);
if ((retval = krb5_parse_name(context, princ_name, &newprinc))) {
com_err(progname, retval, "while parsing '%s'", princ_name);
return;
}
newentry.len = KRB5_KDB_V1_BASE_LENGTH;
newentry.attributes = mblock.flags;
newentry.max_life = mblock.max_life;
newentry.max_renewable_life = mblock.max_rlife;
newentry.expiration = mblock.expiration;
newentry.pw_expiration = mblock.expiration;
if ((retval = krb5_copy_principal(context, newprinc, &newentry.princ))) {
com_err(progname, retval, "while encoding princ to db entry for '%s'",
princ_name);
krb5_free_principal(context, newprinc);
goto error;
}
{
krb5_int32 now;
retval = krb5_timeofday(context, &now);
if (retval) {
com_err(progname, retval, "while fetching date");
krb5_free_principal(context, newprinc);
goto error;
}
retval = krb5_dbe_update_mod_princ_data(context, &newentry, now,
master_princ);
if (retval) {
com_err(progname, retval, "while encoding mod_princ data");
krb5_free_principal(context, newprinc);
goto error;
}
}
{
krb5_data pwd, salt;
krb5_keyblock key;
if ((retval = krb5_principal2salt(context, newprinc, &salt))) {
com_err(progname, retval, "while converting princ to salt for '%s'",
princ_name);
krb5_free_principal(context, newprinc);
goto error;
}
krb5_free_principal(context, newprinc);
pwd.length = strlen(princ_name);
pwd.data = princ_name;
if ((retval = krb5_c_string_to_key(context, master_keyblock.enctype,
&pwd, &salt, &key))) {
com_err(progname,retval,"while converting password to key for '%s'",
princ_name);
krb5_free_data_contents(context, &salt);
goto error;
}
krb5_free_data_contents(context, &salt);
if ((retval = krb5_dbe_create_key_data(context, &newentry))) {
com_err(progname, retval, "while creating key_data for '%s'",
princ_name);
free(key.contents);
goto error;
}
if ((retval = krb5_dbekd_encrypt_key_data(context,&master_keyblock,
&key, NULL, 1,
newentry.key_data))) {
com_err(progname, retval, "while encrypting key for '%s'",
princ_name);
free(key.contents);
goto error;
}
free(key.contents);
}
{
int one = 1;
if ((retval = krb5_db_put_principal(context, &newentry, &one))) {
com_err(progname, retval, "while storing principal date");
goto error;
}
if (one != 1) {
com_err(progname,0,"entry not stored in database (unknown failure)");
goto error;
}
}
fprintf(stdout, "Added %s to database\n", princ_name);
error:
#if 0
krb5_dbe_free_contents(context, &newentry);
#endif
krb5_db_free_principal(context, &newentry, 1);
return;
}
int
set_dbname_help(pname, dbname)
char *pname;
char *dbname;
{
krb5_error_code retval;
int nentries;
krb5_boolean more;
krb5_data pwd, scratch;
char *args[2];
if ((retval = krb5_db_setup_mkey_name(test_context, mkey_name, cur_realm,
0, &master_princ))) {
com_err(pname, retval, "while setting up master key name");
return(1);
}
master_princ_set = 1;
if (mkey_password) {
pwd.data = mkey_password;
pwd.length = strlen(mkey_password);
retval = krb5_principal2salt(test_context, master_princ, &scratch);
if (retval) {
com_err(pname, retval, "while calculated master key salt");
return(1);
}
if ((retval = krb5_c_string_to_key(test_context,
master_keyblock.enctype,
&pwd, &scratch,
&master_keyblock))) {
com_err(pname, retval,
"while transforming master key from password");
return(1);
}
free(scratch.data);
} else {
if ((retval = krb5_db_fetch_mkey(test_context, master_princ,
master_keyblock.enctype, manual_mkey,
FALSE, 0, NULL, NULL,
&master_keyblock))) {
com_err(pname, retval, "while reading master key");
return(1);
}
}
if ((retval = krb5_set_default_realm(test_context, cur_realm))) {
com_err(pname, retval, "setting default realm");
return 1;
}
args[1] = NULL;
args[0] = malloc(sizeof("dbname=") + strlen(dbname));
if (args[0] == NULL) {
com_err(pname, errno, "while setting up db parameters");
return 1;
}
sprintf(args[0], "dbname=%s", dbname);
if ((retval = krb5_db_open(test_context, args, KRB5_KDB_OPEN_RO))) {
com_err(pname, retval, "while initializing database");
return(1);
}
free(args[0]);
if ((retval = krb5_db_verify_master_key(test_context, master_princ,
IGNORE_VNO, &master_keyblock))){
com_err(pname, retval, "while verifying master key");
(void) krb5_db_fini(test_context);
return(1);
}
nentries = 1;
if ((retval = krb5_db_get_principal(test_context, master_princ,
&master_entry, &nentries, &more))) {
com_err(pname, retval, "while retrieving master entry");
(void) krb5_db_fini(test_context);
return(1);
} else if (more) {
com_err(pname, KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE,
"while retrieving master entry");
(void) krb5_db_fini(test_context);
return(1);
} else if (!nentries) {
com_err(pname, KRB5_KDB_NOENTRY, "while retrieving master entry");
(void) krb5_db_fini(test_context);
return(1);
}
mblock.max_life = master_entry.max_life;
mblock.max_rlife = master_entry.max_renewable_life;
mblock.expiration = master_entry.expiration;
mblock.mkvno = master_entry.key_data[0].key_data_kvno;
krb5_db_free_principal(test_context, &master_entry, nentries);
return 0;
}