rewritten to use the kadm5 API

git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@4304 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Assar Westerlund
1998-01-20 21:59:33 +00:00
parent cb36f1acae
commit 7c9e3fd781

View File

@@ -37,31 +37,15 @@
*/
#include "kpasswd_locl.h"
#include <hdb.h>
#include <admin.h>
RCSID("$Id$");
static krb5_context context;
static void *kadm5_handle;
static krb5_log_facility *log_facility;
static sig_atomic_t exit_flag = 0;
#define KPASSWDD_LOG_ERR 0
#define KPASSWDD_LOG_INFO 1
static void
syslog_and_die (const char *m, ...)
{
va_list args;
va_start(args, m);
krb5_vlog (context, log_facility, KPASSWDD_LOG_ERR, m, args);
va_end(args);
exit (1);
}
static char *database = HDB_DEFAULT_DB;
static HDB *db;
static void
send_reply (int s,
struct sockaddr *sa,
@@ -112,9 +96,7 @@ send_reply (int s,
iov[2].iov_len = rest->length;
if (sendmsg (s, &msghdr, 0) < 0)
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"sendmsg: %s",
strerror(errno));
krb5_warn (context, errno, "sendmsg");
}
static int
@@ -131,8 +113,7 @@ make_result (krb5_data *data,
expl);
if (data->data == NULL) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"Out of memory generating error reply");
krb5_warnx (context, "Out of memory generating error reply");
return 1;
}
return 0;
@@ -164,9 +145,7 @@ reply_error (krb5_principal server,
&error_data);
krb5_data_free (&e_data);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"Could not even generate error reply: %s",
krb5_get_err_text (context, ret));
krb5_warn (context, ret, "Could not even generate error reply");
return;
}
send_reply (s, sa, sa_size, NULL, &error_data);
@@ -190,9 +169,7 @@ reply_priv (krb5_auth_context auth_context,
&auth_context,
&ap_rep_data);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"Could not even generate error reply: %s",
krb5_get_err_text (context, ret));
krb5_warn (context, ret, "Could not even generate error reply");
return;
}
@@ -206,9 +183,7 @@ reply_priv (krb5_auth_context auth_context,
NULL);
krb5_data_free (&e_data);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"Could not even generate error reply: %s",
krb5_get_err_text (context, ret));
krb5_warn (context, ret, "Could not even generate error reply");
return;
}
send_reply (s, sa, sa_size, &ap_rep_data, &krb_priv_data);
@@ -235,129 +210,91 @@ change (krb5_auth_context auth_context,
{
krb5_error_code ret;
char *c;
hdb_entry ent;
kadm5_principal_ent_rec ent;
krb5_key_data *kd;
krb5_data salt;
krb5_keyblock new_keyblock, *old_keyblock;
krb5_keyblock new_keyblock;
char *pwd_reason;
int unchanged;
krb5_unparse_name (context, principal, &c);
krb5_log (context, log_facility, KPASSWDD_LOG_INFO,
"Changing password for %s", c);
krb5_warnx (context, "Changing password for %s", c);
free (c);
pwd_reason = passwd_quality_check (pwd_data);
if (pwd_reason != NULL ) {
krb5_log (context, log_facility,
KPASSWDD_LOG_ERR, pwd_reason);
krb5_warnx (context, pwd_reason);
reply_priv (auth_context, s, sa, sa_size, 4, pwd_reason);
return;
}
ret = db->open(context, db, O_RDWR, 0600);
ret = kadm5_get_principal (kadm5_handle,
principal,
&ent,
KADM5_KEY_DATA);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"hdb_open: %s", krb5_get_err_text(context, ret));
reply_priv (auth_context, s, sa, sa_size, 2, "hdb_open failed");
krb5_warn (context, ret, "kadm5_get_principal");
reply_priv (auth_context, s, sa, sa_size, 2,
"kadm5_get_principal failed");
return;
}
krb5_copy_principal (context, principal, &ent.principal);
ret = db->fetch (context, db, &ent);
switch (ret) {
case HDB_ERR_NOENTRY:
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"not found in database");
reply_priv (auth_context, s, sa, sa_size, 2,
"entry not found in database");
goto out;
case 0:
break;
default :
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"dbfetch: %s", krb5_get_err_text(context, ret));
reply_priv (auth_context, s, sa, sa_size, 2,
"db_fetch failed");
goto out;
}
/*
* Compare with the first key to see if it already has been
* changed. If it hasn't, store the new key in the database and
* string2key all the rest of them.
*/
krb5_data_zero (&salt);
krb5_get_salt (principal, &salt);
kd = &ent.key_data[0];
salt.length = kd->key_data_length[1];
salt.data = kd->key_data_contents[1];
memset (&new_keyblock, 0, sizeof(new_keyblock));
old_keyblock = &ent.keys.val[0].key;
krb5_string_to_key_data (pwd_data, &salt,
old_keyblock->keytype, /* XXX */
krb5_string_to_key_data (pwd_data,
&salt,
kd->key_data_type[0],
&new_keyblock);
if (new_keyblock.keytype == old_keyblock->keytype
&& new_keyblock.keyvalue.length == old_keyblock->keyvalue.length
&& memcmp (new_keyblock.keyvalue.data,
old_keyblock->keyvalue.data,
new_keyblock.keyvalue.length) == 0) {
ret = 0;
} else {
Event *e;
int i;
unchanged = new_keyblock.keytype == kd->key_data_type[0]
&& new_keyblock.keyvalue.length == kd->key_data_length[0]
&& memcmp(new_keyblock.keyvalue.data,
kd->key_data_contents[0],
new_keyblock.keyvalue.length) == 0;
free_EncryptionKey (old_keyblock);
memset (old_keyblock, 0, sizeof(*old_keyblock));
old_keyblock->keytype = new_keyblock.keytype;
krb5_data_copy (&old_keyblock->keyvalue,
new_keyblock.keyvalue.data,
new_keyblock.keyvalue.length);
for(i = 1; i < ent.keys.len; ++i) {
free_Key (&ent.keys.val[i]);
krb5_string_to_key_data (pwd_data,
&salt,
ent.keys.val[i].key.keytype,
&ent.keys.val[i].key);
}
ent.kvno++;
e = malloc(sizeof(*e));
e->time = time(NULL);
krb5_copy_principal (context, principal, &e->principal);
if (ent.modified_by) {
free_Event (ent.modified_by);
free (ent.modified_by);
}
ent.modified_by = e;
if (ent.pw_end){
int t = krb5_config_get_time(context, NULL,
"libdefaults",
"pw_expiration", NULL);
if(t > 0)
*ent.pw_end = e->time + t;
else{
free(ent.pw_end);
ent.pw_end = NULL;
}
}
ret = db->store (context, db, 1, &ent);
}
krb5_data_free (&salt);
krb5_free_keyblock_contents (context, &new_keyblock);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"dbstore: %s", krb5_get_err_text (context, ret));
reply_priv (auth_context, s, sa, sa_size, 2,
"db_store failed");
if (unchanged) {
ret = 0;
} else {
reply_priv (auth_context, s, sa, sa_size, 0, "password changed");
char *tmp;
tmp = malloc (pwd_data->length + 1);
if (tmp == NULL) {
krb5_warnx (context, "malloc: out of memory");
reply_priv (auth_context, s, sa, sa_size, 2,
"malloc failed");
goto out;
}
memcpy (tmp, pwd_data->data, pwd_data->length);
tmp[pwd_data->length] = '\0';
ret = kadm5_chpass_principal (kadm5_handle,
principal,
tmp);
memset (tmp, 0, pwd_data->length);
free (tmp);
if (ret) {
krb5_warn (context, ret, "kadm5_s_chpass_principal");
reply_priv (auth_context, s, sa, sa_size, 2,
"change failed");
goto out;
}
}
reply_priv (auth_context, s, sa, sa_size, 0, "password changed");
out:
hdb_free_entry (context, &ent);
db->close (context, db);
kadm5_free_principal_ent (kadm5_handle, &ent);
}
static int
@@ -380,14 +317,12 @@ verify (krb5_auth_context *auth_context,
pkt_ver = (msg[2] << 8) | (msg[3]);
ap_req_len = (msg[4] << 8) | (msg[5]);
if (pkt_len != len) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"Strange len: %d != %d", pkt_len, len);
krb5_warnx (context, "Strange len: %d != %d", pkt_len, len);
reply_error (server, s, sa, sa_size, 0, 1, "bad length");
return 1;
}
if (pkt_ver != 0x0001) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"Bad version (%d)", pkt_ver);
krb5_warnx (context, "Bad version (%d)", pkt_ver);
reply_error (server, s, sa, sa_size, 0, 1, "bad version");
return 1;
}
@@ -403,15 +338,13 @@ verify (krb5_auth_context *auth_context,
NULL,
ticket);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR, "krb5_rd_req: %s",
krb5_get_err_text(context, ret));
krb5_warn (context, ret, "krb5_rd_req");
reply_error (server, s, sa, sa_size, ret, 3, "rd_req failed");
return 1;
}
if (!(*ticket)->ticket.flags.initial) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"initial flag not set");
krb5_warnx (context, "initial flag not set");
reply_error (server, s, sa, sa_size, ret, 1,
"initial flag not set");
goto out;
@@ -426,8 +359,7 @@ verify (krb5_auth_context *auth_context,
NULL);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR, "krb5_rd_priv: %s",
krb5_get_err_text(context, ret));
krb5_warn (context, ret, "krb5_rd_priv");
reply_error (server, s, sa, sa_size, ret, 3, "rd_priv failed");
goto out;
}
@@ -456,9 +388,7 @@ process (krb5_principal server,
ret = krb5_auth_con_init (context, &auth_context);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"krb5_auth_con_init: %s",
krb5_get_err_text(context, ret));
krb5_warn (context, ret, "krb5_auth_con_init");
return;
}
@@ -467,9 +397,7 @@ process (krb5_principal server,
ret = krb5_sockaddr2address (sa, &other_addr);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"krb5_sockaddr2address: %s",
krb5_get_err_text(context, ret));
krb5_warn (context, ret, "krb5_sockaddr2address");
goto out;
}
@@ -479,9 +407,7 @@ process (krb5_principal server,
&other_addr);
krb5_free_address (context, &other_addr);
if (ret) {
krb5_log (context, log_facility, KPASSWDD_LOG_ERR,
"krb5_auth_con_setaddr: %s",
krb5_get_err_text(context, ret));
krb5_warn (context, ret, "krb5_auth_con_setaddr");
goto out;
}
@@ -519,13 +445,12 @@ doit (int port)
sa_max_size = krb5_max_sockaddr_size ();
sa_buf = malloc (sa_max_size);
if (sa_buf == NULL)
syslog_and_die ("out of memory");
krb5_errx (context, 1, "out of memory");
sa = (struct sockaddr *)sa_buf;
ret = krb5_get_default_realm (context, &realm);
if (ret)
syslog_and_die ("krb5_get_default_realm: %s",
krb5_get_err_text(context, ret));
krb5_err (context, 1, ret, "krb5_get_default_realm");
ret = krb5_build_principal (context,
&server,
@@ -535,19 +460,19 @@ doit (int port)
"changepw",
NULL);
if (ret)
syslog_and_die ("krb5_build_principal_ext: %s",
krb5_get_err_text(context, ret));
krb5_err (context, 1, ret, "krb5_build_principal");
free (realm);
ret = krb5_get_all_client_addrs (&addrs);
if (ret)
syslog_and_die ("krb5_get_all_clients_addrs: %s",
krb5_get_err_text(context, ret));
krb5_err (context, 1, ret, "krb5_get_all_client_addrs");
n = addrs.len;
sockets = malloc (n * sizeof(*sockets));
if (sockets == NULL)
krb5_errx (context, 1, "out of memory");
maxfd = 0;
FD_ZERO(&real_fdset);
for (i = 0; i < n; ++i) {
@@ -557,10 +482,9 @@ doit (int port)
sockets[i] = socket (sa->sa_family, SOCK_DGRAM, 0);
if (sockets[i] < 0)
syslog_and_die ("socket: %m");
krb5_err (context, 1, errno, "socket");
if (bind (sockets[i], sa, sa_size) < 0)
syslog_and_die ("bind: %m");
krb5_err (context, 1, errno, "bind");
maxfd = max (maxfd, sockets[i]);
FD_SET(sockets[i], &real_fdset);
}
@@ -574,7 +498,7 @@ doit (int port)
if (errno == EINTR)
continue;
else
syslog_and_die ("select: %m");
krb5_err (context, 1, errno, "select");
for (i = 0; i < n; ++i)
if (FD_ISSET(sockets[i], &fdset)) {
u_char buf[BUFSIZ];
@@ -586,7 +510,7 @@ doit (int port)
if(errno == EINTR)
break;
else
syslog_and_die ("recvfrom: %m");
krb5_err (context, 1, errno, "recvfrom");
process (server, sockets[i],
&addrs.val[i],
@@ -611,21 +535,24 @@ int
main (int argc, char **argv)
{
krb5_error_code ret;
char *keyfile = NULL;
kadm5_config_params conf;
krb5_init_context (&context);
set_progname (argv[0]);
krb5_openlog (context, "kpasswdd", &log_facility);
krb5_set_warn_dest(context, log_facility);
ret = hdb_create (context, &db, database);
memset (&conf, 0, sizeof(conf));
ret = kadm5_s_init_with_password_ctx(context,
KADM5_ADMIN_SERVICE,
"password",
KADM5_ADMIN_SERVICE,
&conf, 0, 0,
&kadm5_handle);
if (ret)
syslog_and_die ("Failed to open database %s: %s",
database, krb5_get_err_text(context, ret));
ret = hdb_set_master_key(context, db, keyfile);
if (ret)
syslog_and_die ("Failed to set master key: %s",
krb5_get_err_text(context, ret));
krb5_err (context, 1, ret, "kadm5_s_init_with_password_ctx");
#ifdef HAVE_SIGACTION
{