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:
@@ -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
|
||||
{
|
||||
|
Reference in New Issue
Block a user