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