From 40a0ac5cfc7e7a11329b458f8266905bcd9b520c Mon Sep 17 00:00:00 2001 From: Assar Westerlund Date: Thu, 26 Feb 1998 23:55:37 +0000 Subject: [PATCH] more code git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@4460 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/kadm5/iprop.h | 54 ++++++++++++++ lib/kadm5/ipropd_master.c | 143 ++++++++++++++++++++++++++++++++++++-- lib/kadm5/ipropd_slave.c | 109 ++++++++++++++++++++++++++++- lib/kadm5/kadm5_locl.h | 17 +++-- lib/kadm5/log.c | 44 ++++++++++++ 5 files changed, 352 insertions(+), 15 deletions(-) create mode 100644 lib/kadm5/iprop.h diff --git a/lib/kadm5/iprop.h b/lib/kadm5/iprop.h new file mode 100644 index 000000000..db3f0ac5b --- /dev/null +++ b/lib/kadm5/iprop.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __IPROP_H__ +#define __IPROP_H__ + +#include "kadm5_locl.h" + +#define IPROP_VERSION "iprop-0.0" + +#define KADM5_SLAVE_ACL HDB_DB_DIR "/slaves" + +#define IPROP_NAME "iprop" + +enum iprop_cmd { I_HAVE = 1, FOR_YOU = 2 }; + +#endif /* __IPROP_H__ */ diff --git a/lib/kadm5/ipropd_master.c b/lib/kadm5/ipropd_master.c index c5a3181cf..7e4933bd9 100644 --- a/lib/kadm5/ipropd_master.c +++ b/lib/kadm5/ipropd_master.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. */ -#include "kadm5_locl.h" +#include "iprop.h" RCSID("$Id$"); @@ -179,6 +179,134 @@ error: free(s); } +static void +remove_slave (krb5_context context, slave *s, slave **root) +{ + slave **p; + + close (s->fd); + free (s->name); + krb5_auth_con_free (context, s->ac); + + for (p = root; *p; p = &(*p)->next) + if (*p == s) { + *p = s->next; + break; + } + free (s); +} + +static int +send_diffs (krb5_context context, slave *s, int log_fd) +{ + krb5_storage *sp, *data_sp; + u_int32_t ver; + time_t timestamp; + enum kadm_ops op; + u_int32_t len; + off_t right, left; + krb5_data data; + krb5_data priv_data; + int ret = 0; + u_char buf[4]; + + sp = kadm5_log_goto_end (log_fd); + right = sp->seek(sp, 0, SEEK_CUR); + for (;;) { + if (kadm5_log_previous (sp, &ver, ×tamp, &op, &len)) + abort (); + left = sp->seek(sp, -16, SEEK_CUR); + if (ver == s->version) + break; + } + krb5_data_alloc (&data, right - left + 4); + sp->fetch (sp, (char *)data.data + 4, data.length - 4); + krb5_storage_free(sp); + + data_sp = krb5_storage_from_mem (data.data, 4); + krb5_store_int32 (data_sp, FOR_YOU); + krb5_storage_free(sp); + + ret = krb5_mk_priv (context, s->ac, &data, &priv_data, NULL); + krb5_data_free(&data); + if (ret) { + krb5_warn (context, ret, "krb_mk_priv"); + return 0; + } + buf[0] = (priv_data.length >> 24) & 0xFF; + buf[1] = (priv_data.length >> 16) & 0xFF; + buf[2] = (priv_data.length >> 8) & 0xFF; + buf[3] = (priv_data.length >> 0) & 0xFF; + ret = krb5_net_write (context, &s->fd, buf, 4); + if (ret < 0) { + krb5_data_free (&priv_data); + krb5_warn (context, ret, "krb_net_write"); + return 1; + } + ret = krb5_net_write (context, &s->fd, priv_data.data, priv_data.length); + krb5_data_free (&priv_data); + if (ret < 0) { + krb5_warn (context, ret, "krb_net_write"); + return 1; + } + return 0; +} + +static int +process_msg (krb5_context context, slave *s, int log_fd) +{ + int ret = 0; + u_int32_t len; + krb5_data in, out; + krb5_storage *sp; + int32_t tmp; + u_char buf[8]; + + ret = krb5_net_read (context, &s->fd, buf, 4); + if (ret == 0) { + return 1; + } + if (ret < 0) { + krb5_warn(context, errno, "krb5_net_read"); + return 1; + } + len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + ret = krb5_data_alloc (&in, len); + if (ret) { + krb5_warn (context, ret, "krb5_data_alloc"); + return 1; + } + ret = krb5_net_read(context, &s->fd, in.data, in.length); + if (ret < 0) { + krb5_warn(context, errno, "krb5_net_read"); + krb5_data_free (&in); + return 1; + } + ret = krb5_rd_priv (context, s->ac, &in, &out, NULL); + krb5_data_free (&in); + if (ret) { + krb5_warn (context, ret, "krb5_rd_priv"); + return 1; + } + + sp = krb5_storage_from_mem (out.data, out.length); + krb5_ret_int32 (sp, &tmp); + switch (tmp) { + case I_HAVE : + krb5_ret_int32 (sp, &tmp); + s->version = tmp; + ret = send_diffs (context, s, log_fd); + break; + case FOR_YOU : + default : + krb5_warnx (context, "Ignoring command %d", tmp); + break; + } + + krb5_data_free (&out); + return ret; +} + int main(int argc, char **argv) { @@ -190,7 +318,7 @@ main(int argc, char **argv) int signal_fd, listen_fd; int log_fd; slave *slaves = NULL; - u_int32_t version, old_version = 0; + u_int32_t current_version, old_version = 0; set_progname(argv[0]); @@ -242,9 +370,11 @@ main(int argc, char **argv) else krb5_err (context, 1, errno, "select"); } - kadm5_log_get_version (log_fd, &version); - if (version > old_version) - ; /* XXX - send out updates */ + kadm5_log_get_version (log_fd, ¤t_version); + if (current_version > old_version) { + for (p = slaves; p != NULL; p = p->next) + send_diffs (context, p, log_fd); + } if (ret && FD_ISSET(signal_fd, &readset)) { struct sockaddr_un peer_addr; size_t peer_len = sizeof(peer_addr); @@ -264,7 +394,8 @@ main(int argc, char **argv) for(p = slaves; ret-- && p != NULL; p = p->next) if (FD_ISSET(p->fd, &readset)) { - /* XXX */ + if(process_msg (context, p, log_fd)) + remove_slave (context, p, &slaves); } } diff --git a/lib/kadm5/ipropd_slave.c b/lib/kadm5/ipropd_slave.c index 0d3536bd6..94d4f7bd2 100644 --- a/lib/kadm5/ipropd_slave.c +++ b/lib/kadm5/ipropd_slave.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. */ -#include "kadm5_locl.h" +#include "iprop.h" RCSID("$Id$"); @@ -97,6 +97,69 @@ get_creds(krb5_context context, krb5_ccache *cache) if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); } +static void +ihave (krb5_context context, krb5_auth_context auth_context, + int fd, u_int32_t version) +{ + int ret; + u_char buf[8]; + krb5_storage *sp; + krb5_data data, priv_data; + + sp = krb5_storage_from_mem (buf, 8); + krb5_store_int32 (sp, I_HAVE); + krb5_store_int32 (sp, version); + krb5_storage_free (sp); + data.length = 8; + data.data = buf; + + ret = krb5_mk_priv (context, auth_context, &data, &priv_data, NULL); + if (ret) + krb5_err (context, 1, ret, "krb_mk_priv"); + buf[0] = (priv_data.length >> 24) & 0xFF; + buf[1] = (priv_data.length >> 16) & 0xFF; + buf[2] = (priv_data.length >> 8) & 0xFF; + buf[3] = (priv_data.length >> 0) & 0xFF; + ret = krb5_net_write (context, &fd, buf, 4); + if (ret < 0) + krb5_err (context, 1, ret, "krb_net_write"); + ret = krb5_net_write (context, &fd, priv_data.data, priv_data.length); + krb5_data_free (&priv_data); + if (ret < 0) + krb5_err (context, 1, ret, "krb_net_write"); +} + +static void +receive (krb5_context context, + krb5_storage *sp, + kadm5_server_context *server_context) +{ + int ret; + + for (;;) { + int32_t vers, len, timestamp, tmp; + enum kadm_ops op; + + if(krb5_ret_int32 (sp, &vers) != 0) + return; + krb5_ret_int32 (sp, ×tamp); + krb5_ret_int32 (sp, &tmp); + op = tmp; + krb5_ret_int32 (sp, &len); + if (tmp < server_context->log_context.version) { + sp->seek(sp, len, SEEK_CUR); + } else { + ret = kadm5_log_replay (server_context, + op, vers, len, sp); + if (ret) + krb5_warn (context, ret, "kadm5_log_replay"); + else + server_context->log_context.version = vers; + } + sp->seek (sp, 8, SEEK_CUR); + } +} + int main(int argc, char **argv) { @@ -126,6 +189,12 @@ main(int argc, char **argv) server_context = (kadm5_server_context *)kadm_handle; + ret = kadm5_log_init (server_context); + if (ret) + krb5_err (context, 1, ret, "kadm5_log_init"); + + get_creds(context, &ccache); + master_fd = connect_to_master (context, argv[1]); ret = krb5_sname_to_principal (context, argv[1], IPROP_NAME, @@ -133,8 +202,6 @@ main(int argc, char **argv) if (ret) krb5_err (context, 1, ret, "krb5_sname_to_principal"); - get_creds(context, &ccache); - auth_context = NULL; ret = krb5_sendauth (context, &auth_context, &master_fd, IPROP_VERSION, NULL, server, @@ -143,5 +210,41 @@ main(int argc, char **argv) if (ret) krb5_err (context, 1, ret, "krb5_sendauth"); + ihave (context, auth_context, master_fd, + server_context->log_context.version); + + for (;;) { + u_char buf[4]; + int ret; + krb5_data data, out; + u_int32_t len; + krb5_storage *sp; + int32_t tmp; + + ret = krb5_net_read (context, &master_fd, buf, 4); + if (ret != 4) + krb5_err (context, 1, ret, "krb5_net_read"); + len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + ret = krb5_data_alloc (&data, len); + if (ret) + krb5_err (context, 1, ret, "krb5_data_alloc"); + ret = krb5_net_read (context, &master_fd, data.data, data.length); + if (ret) + krb5_err (context, 1, ret, "krb5_net_read"); + ret = krb5_rd_priv (context, auth_context, &data, &out, NULL); + if (ret) + krb5_err (context, 1, ret, "krb5_rd_priv"); + sp = krb5_storage_from_mem (out.data, out.length); + krb5_ret_int32 (sp, &tmp); + switch (tmp) { + case FOR_YOU : + receive (context, sp, server_context); + case I_HAVE : + default : + krb5_warnx (context, "Ignoring command %d", tmp); + break; + } + } + return 0; } diff --git a/lib/kadm5/kadm5_locl.h b/lib/kadm5/kadm5_locl.h index bcb3fdbdf..75b0e7dfc 100644 --- a/lib/kadm5/kadm5_locl.h +++ b/lib/kadm5/kadm5_locl.h @@ -49,6 +49,7 @@ #include #include #include +#include #ifdef HAVE_UNISTD_H #include #endif @@ -287,12 +288,16 @@ kadm5_log_replay (kadm5_server_context *context, u_int32_t len, krb5_storage *sp); +krb5_storage * +kadm5_log_goto_end (int fd); + +kadm5_ret_t +kadm5_log_previous (krb5_storage *sp, + u_int32_t *ver, + time_t *timestamp, + enum kadm_ops *op, + u_int32_t *len); + #define KADM5_LOG_SIGNAL HDB_DB_DIR "/signal" -#define IPROP_VERSION "iprop-0.0" - -#define KADM5_SLAVE_ACL HDB_DB_DIR "/slaves" - -#define IPROP_NAME "iprop" - #endif /* __KADM5_LOCL_H__ */ diff --git a/lib/kadm5/log.c b/lib/kadm5/log.c index 0aad33e7a..2e67b10f9 100644 --- a/lib/kadm5/log.c +++ b/lib/kadm5/log.c @@ -596,6 +596,50 @@ kadm5_log_foreach (kadm5_server_context *context, return 0; } +/* + * Go to end of log. + */ + +krb5_storage * +kadm5_log_goto_end (int fd) +{ + krb5_storage *sp; + + sp = krb5_storage_from_fd (fd); + sp->seek(sp, 0, SEEK_END); + return sp; +} + +/* + * Return previous log entry. + */ + +kadm5_ret_t +kadm5_log_previous (krb5_storage *sp, + u_int32_t *ver, + time_t *timestamp, + enum kadm_ops *op, + u_int32_t *len) +{ + int32_t tmp; + + sp->seek(sp, -8, SEEK_CUR); + krb5_ret_int32 (sp, &tmp); + *len = tmp; + krb5_ret_int32 (sp, &tmp); + *ver = tmp; + sp->seek(sp, -(48 + *len), SEEK_CUR); + krb5_ret_int32 (sp, &tmp); + assert(tmp == *ver); + krb5_ret_int32 (sp, &tmp); + *timestamp = tmp; + krb5_ret_int32 (sp, &tmp); + *op = tmp; + krb5_ret_int32 (sp, &tmp); + assert(tmp == *len); + return 0; +} + /* * Replay a record from the log */