#include "string_table.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <k5-int.h>
#include <kdb.h>
#include <kadm5/admin.h>
#include <adm_proto.h>
#include "fake-addrinfo.h"
#include <krb5.h>
#include <kdb.h>
#include "kdb5_util.h"
static int add_admin_princ(void *handle, krb5_context context,
char *name, char *realm, int attrs, int lifetime);
static int add_admin_princs(void *handle, krb5_context context, char *realm);
#define ERR 1
#define OK 0
#define ADMIN_LIFETIME 60*60*3
#define CHANGEPW_LIFETIME 60*5
int kadm5_create(kadm5_config_params *params)
{
int retval;
krb5_context context;
kadm5_config_params lparams;
if ((retval = kadm5_init_krb5_context(&context)))
exit(ERR);
if ((retval = kadm5_get_config_params(context, 1,
params, &lparams))) {
com_err(progname, retval, "while looking up the Kerberos configuration");
return 1;
}
retval = kadm5_create_magic_princs(&lparams, context);
kadm5_free_config_params(context, &lparams);
krb5_free_context(context);
return retval;
}
int kadm5_create_magic_princs(kadm5_config_params *params,
krb5_context context)
{
int retval;
void *handle;
retval = krb5_klog_init(context, "admin_server", progname, 0);
if (retval)
return retval;
if ((retval = kadm5_init(progname, NULL, NULL, params,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_2,
db5util_db_args,
&handle))) {
com_err(progname, retval, "while initializing the Kerberos admin interface");
return retval;
}
retval = add_admin_princs(handle, context, params->realm);
kadm5_destroy(handle);
krb5_klog_close(context);
return retval;
}
static char *build_name_with_realm(char *name, char *realm)
{
char *n;
n = (char *) malloc(strlen(name) + strlen(realm) + 2);
sprintf(n, "%s@%s", name, realm);
return n;
}
static int add_admin_princs(void *handle, krb5_context context, char *realm)
{
krb5_error_code ret = 0;
char *service_name = 0, *p;
char localname[MAXHOSTNAMELEN];
struct addrinfo *ai, ai_hints;
int gai_error;
if (gethostname(localname, MAXHOSTNAMELEN)) {
ret = errno;
perror("gethostname");
goto clean_and_exit;
}
memset(&ai_hints, 0, sizeof(ai_hints));
ai_hints.ai_flags = AI_CANONNAME;
gai_error = getaddrinfo(localname, (char *)NULL, &ai_hints, &ai);
if (gai_error) {
ret = EINVAL;
fprintf(stderr, "getaddrinfo(%s): %s\n", localname,
gai_strerror(gai_error));
goto clean_and_exit;
}
if (ai->ai_canonname == NULL) {
ret = EINVAL;
fprintf(stderr,
"getaddrinfo(%s): Cannot determine canonical hostname.\n",
localname);
freeaddrinfo(ai);
goto clean_and_exit;
}
for (p = ai->ai_canonname; *p; p++) {
#ifdef isascii
if (!isascii(*p))
continue;
#else
if (*p < ' ')
continue;
if (*p > '~')
continue;
#endif
if (!isupper(*p))
continue;
*p = tolower(*p);
}
if (asprintf(&service_name, "kadmin/%s", ai->ai_canonname) < 0) {
ret = ENOMEM;
fprintf(stderr, "Out of memory\n");
freeaddrinfo(ai);
goto clean_and_exit;
}
freeaddrinfo(ai);
if ((ret = add_admin_princ(handle, context,
service_name, realm,
KRB5_KDB_DISALLOW_TGT_BASED,
ADMIN_LIFETIME)))
goto clean_and_exit;
if ((ret = add_admin_princ(handle, context,
KADM5_ADMIN_SERVICE, realm,
KRB5_KDB_DISALLOW_TGT_BASED,
ADMIN_LIFETIME)))
goto clean_and_exit;
if ((ret = add_admin_princ(handle, context,
KADM5_CHANGEPW_SERVICE, realm,
KRB5_KDB_DISALLOW_TGT_BASED |
KRB5_KDB_PWCHANGE_SERVICE,
CHANGEPW_LIFETIME)))
goto clean_and_exit;
clean_and_exit:
free(service_name);
return ret;
}
int add_admin_princ(void *handle, krb5_context context,
char *name, char *realm, int attrs, int lifetime)
{
char *fullname;
krb5_error_code ret;
kadm5_principal_ent_rec ent;
memset(&ent, 0, sizeof(ent));
fullname = build_name_with_realm(name, realm);
ret = krb5_parse_name(context, fullname, &ent.principal);
if (ret) {
com_err(progname, ret, str_PARSE_NAME);
return(ERR);
}
ent.max_life = lifetime;
ent.attributes = attrs | KRB5_KDB_DISALLOW_ALL_TIX;
ret = kadm5_create_principal(handle, &ent,
(KADM5_PRINCIPAL | KADM5_MAX_LIFE |
KADM5_ATTRIBUTES),
"to-be-random");
if (ret) {
if (ret != KADM5_DUP) {
com_err(progname, ret, str_PUT_PRINC, fullname);
krb5_free_principal(context, ent.principal);
free(fullname);
return ERR;
}
} else {
ret = kadm5_randkey_principal(handle, ent.principal, NULL, NULL);
if (ret) {
com_err(progname, ret, str_RANDOM_KEY, fullname);
krb5_free_principal(context, ent.principal);
free(fullname);
return ERR;
}
ent.attributes = attrs;
ret = kadm5_modify_principal(handle, &ent, KADM5_ATTRIBUTES);
if (ret) {
com_err(progname, ret, str_PUT_PRINC, fullname);
krb5_free_principal(context, ent.principal);
free(fullname);
return ERR;
}
}
krb5_free_principal(context, ent.principal);
free(fullname);
return OK;
}