1b528cefcSMark Murray /* 28373020dSJacques Vidrine * Copyright (c) 1997 - 2002 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #include "iprop.h" 358373020dSJacques Vidrine #include <rtbl.h> 36b528cefcSMark Murray 37bbd80c28SJacques Vidrine RCSID("$Id: ipropd_master.c,v 1.29 2003/03/19 11:56:38 lha Exp $"); 385e9cd1aeSAssar Westerlund 395e9cd1aeSAssar Westerlund static krb5_log_facility *log_facility; 40b528cefcSMark Murray 41bbd80c28SJacques Vidrine const char *slave_stats_file = KADM5_SLAVE_STATS; 42bbd80c28SJacques Vidrine 43b528cefcSMark Murray static int 44b528cefcSMark Murray make_signal_socket (krb5_context context) 45b528cefcSMark Murray { 46b528cefcSMark Murray struct sockaddr_un addr; 47b528cefcSMark Murray int fd; 48b528cefcSMark Murray 49b528cefcSMark Murray fd = socket (AF_UNIX, SOCK_DGRAM, 0); 50b528cefcSMark Murray if (fd < 0) 51b528cefcSMark Murray krb5_err (context, 1, errno, "socket AF_UNIX"); 52b528cefcSMark Murray memset (&addr, 0, sizeof(addr)); 53b528cefcSMark Murray addr.sun_family = AF_UNIX; 545e9cd1aeSAssar Westerlund strlcpy (addr.sun_path, KADM5_LOG_SIGNAL, sizeof(addr.sun_path)); 55b528cefcSMark Murray unlink (addr.sun_path); 56b528cefcSMark Murray if (bind (fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) 57b528cefcSMark Murray krb5_err (context, 1, errno, "bind %s", addr.sun_path); 58b528cefcSMark Murray return fd; 59b528cefcSMark Murray } 60b528cefcSMark Murray 61b528cefcSMark Murray static int 62b528cefcSMark Murray make_listen_socket (krb5_context context) 63b528cefcSMark Murray { 64b528cefcSMark Murray int fd; 65b528cefcSMark Murray int one = 1; 66b528cefcSMark Murray struct sockaddr_in addr; 67b528cefcSMark Murray 68b528cefcSMark Murray fd = socket (AF_INET, SOCK_STREAM, 0); 69b528cefcSMark Murray if (fd < 0) 70b528cefcSMark Murray krb5_err (context, 1, errno, "socket AF_INET"); 714137ff4cSJacques Vidrine setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); 72b528cefcSMark Murray memset (&addr, 0, sizeof(addr)); 73b528cefcSMark Murray addr.sin_family = AF_INET; 745e9cd1aeSAssar Westerlund addr.sin_port = krb5_getportbyname (context, 755e9cd1aeSAssar Westerlund IPROP_SERVICE, "tcp", IPROP_PORT); 76b528cefcSMark Murray if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) 77b528cefcSMark Murray krb5_err (context, 1, errno, "bind"); 78b528cefcSMark Murray if (listen(fd, SOMAXCONN) < 0) 79b528cefcSMark Murray krb5_err (context, 1, errno, "listen"); 80b528cefcSMark Murray return fd; 81b528cefcSMark Murray } 82b528cefcSMark Murray 83b528cefcSMark Murray struct slave { 84b528cefcSMark Murray int fd; 85b528cefcSMark Murray struct sockaddr_in addr; 86b528cefcSMark Murray char *name; 87b528cefcSMark Murray krb5_auth_context ac; 88b528cefcSMark Murray u_int32_t version; 898373020dSJacques Vidrine time_t seen; 908373020dSJacques Vidrine unsigned long flags; 918373020dSJacques Vidrine #define SLAVE_F_DEAD 0x1 92b528cefcSMark Murray struct slave *next; 93b528cefcSMark Murray }; 94b528cefcSMark Murray 95b528cefcSMark Murray typedef struct slave slave; 96b528cefcSMark Murray 97b528cefcSMark Murray static int 98b528cefcSMark Murray check_acl (krb5_context context, const char *name) 99b528cefcSMark Murray { 100b528cefcSMark Murray FILE *fp; 101b528cefcSMark Murray char buf[256]; 102b528cefcSMark Murray int ret = 1; 103b528cefcSMark Murray 104b528cefcSMark Murray fp = fopen (KADM5_SLAVE_ACL, "r"); 105b528cefcSMark Murray if (fp == NULL) 106b528cefcSMark Murray return 1; 107b528cefcSMark Murray while (fgets(buf, sizeof(buf), fp) != NULL) { 108b528cefcSMark Murray if (buf[strlen(buf) - 1 ] == '\n') 109b528cefcSMark Murray buf[strlen(buf) - 1 ] = '\0'; 110b528cefcSMark Murray if (strcmp (buf, name) == 0) { 111b528cefcSMark Murray ret = 0; 112b528cefcSMark Murray break; 113b528cefcSMark Murray } 114b528cefcSMark Murray } 115b528cefcSMark Murray fclose (fp); 116b528cefcSMark Murray return ret; 117b528cefcSMark Murray } 118b528cefcSMark Murray 119b528cefcSMark Murray static void 1208373020dSJacques Vidrine slave_seen(slave *s) 1218373020dSJacques Vidrine { 1228373020dSJacques Vidrine s->seen = time(NULL); 1238373020dSJacques Vidrine } 1248373020dSJacques Vidrine 1258373020dSJacques Vidrine static void 1268373020dSJacques Vidrine slave_dead(slave *s) 1278373020dSJacques Vidrine { 128bbd80c28SJacques Vidrine if (s->fd >= 0) { 129bbd80c28SJacques Vidrine close (s->fd); 130bbd80c28SJacques Vidrine s->fd = -1; 131bbd80c28SJacques Vidrine } 1328373020dSJacques Vidrine s->flags |= SLAVE_F_DEAD; 1338373020dSJacques Vidrine slave_seen(s); 1348373020dSJacques Vidrine } 1358373020dSJacques Vidrine 1368373020dSJacques Vidrine static void 1378373020dSJacques Vidrine remove_slave (krb5_context context, slave *s, slave **root) 1388373020dSJacques Vidrine { 1398373020dSJacques Vidrine slave **p; 1408373020dSJacques Vidrine 1418373020dSJacques Vidrine if (s->fd >= 0) 1428373020dSJacques Vidrine close (s->fd); 1438373020dSJacques Vidrine if (s->name) 1448373020dSJacques Vidrine free (s->name); 1458373020dSJacques Vidrine if (s->ac) 1468373020dSJacques Vidrine krb5_auth_con_free (context, s->ac); 1478373020dSJacques Vidrine 1488373020dSJacques Vidrine for (p = root; *p; p = &(*p)->next) 1498373020dSJacques Vidrine if (*p == s) { 1508373020dSJacques Vidrine *p = s->next; 1518373020dSJacques Vidrine break; 1528373020dSJacques Vidrine } 1538373020dSJacques Vidrine free (s); 1548373020dSJacques Vidrine } 1558373020dSJacques Vidrine 1568373020dSJacques Vidrine static void 1575e9cd1aeSAssar Westerlund add_slave (krb5_context context, krb5_keytab keytab, slave **root, int fd) 158b528cefcSMark Murray { 159b528cefcSMark Murray krb5_principal server; 160b528cefcSMark Murray krb5_error_code ret; 161b528cefcSMark Murray slave *s; 1625e9cd1aeSAssar Westerlund socklen_t addr_len; 163b528cefcSMark Murray krb5_ticket *ticket = NULL; 164b528cefcSMark Murray char hostname[128]; 165b528cefcSMark Murray 166b528cefcSMark Murray s = malloc(sizeof(*s)); 167b528cefcSMark Murray if (s == NULL) { 168b528cefcSMark Murray krb5_warnx (context, "add_slave: no memory"); 169b528cefcSMark Murray return; 170b528cefcSMark Murray } 171b528cefcSMark Murray s->name = NULL; 172b528cefcSMark Murray s->ac = NULL; 173b528cefcSMark Murray 174b528cefcSMark Murray addr_len = sizeof(s->addr); 175b528cefcSMark Murray s->fd = accept (fd, (struct sockaddr *)&s->addr, &addr_len); 176b528cefcSMark Murray if (s->fd < 0) { 177b528cefcSMark Murray krb5_warn (context, errno, "accept"); 178b528cefcSMark Murray goto error; 179b528cefcSMark Murray } 180b528cefcSMark Murray gethostname(hostname, sizeof(hostname)); 181b528cefcSMark Murray ret = krb5_sname_to_principal (context, hostname, IPROP_NAME, 182b528cefcSMark Murray KRB5_NT_SRV_HST, &server); 183b528cefcSMark Murray if (ret) { 184b528cefcSMark Murray krb5_warn (context, ret, "krb5_sname_to_principal"); 185b528cefcSMark Murray goto error; 186b528cefcSMark Murray } 187b528cefcSMark Murray 188b528cefcSMark Murray ret = krb5_recvauth (context, &s->ac, &s->fd, 1895e9cd1aeSAssar Westerlund IPROP_VERSION, server, 0, keytab, &ticket); 190b528cefcSMark Murray krb5_free_principal (context, server); 191b528cefcSMark Murray if (ret) { 192b528cefcSMark Murray krb5_warn (context, ret, "krb5_recvauth"); 193b528cefcSMark Murray goto error; 194b528cefcSMark Murray } 195b528cefcSMark Murray ret = krb5_unparse_name (context, ticket->client, &s->name); 196b528cefcSMark Murray if (ret) { 197b528cefcSMark Murray krb5_warn (context, ret, "krb5_unparse_name"); 198b528cefcSMark Murray goto error; 199b528cefcSMark Murray } 200b528cefcSMark Murray if (check_acl (context, s->name)) { 201b528cefcSMark Murray krb5_warnx (context, "%s not in acl", s->name); 202b528cefcSMark Murray goto error; 203b528cefcSMark Murray } 204b528cefcSMark Murray krb5_free_ticket (context, ticket); 2058373020dSJacques Vidrine ticket = NULL; 2068373020dSJacques Vidrine 2078373020dSJacques Vidrine { 2088373020dSJacques Vidrine slave *l = *root; 2098373020dSJacques Vidrine 2108373020dSJacques Vidrine while (l) { 2118373020dSJacques Vidrine if (strcmp(l->name, s->name) == 0) 2128373020dSJacques Vidrine break; 2138373020dSJacques Vidrine l = l->next; 2148373020dSJacques Vidrine } 2158373020dSJacques Vidrine if (l) { 2168373020dSJacques Vidrine if (l->flags & SLAVE_F_DEAD) { 2178373020dSJacques Vidrine remove_slave(context, l, root); 2188373020dSJacques Vidrine } else { 2198373020dSJacques Vidrine krb5_warnx (context, "second connection from %s", s->name); 2208373020dSJacques Vidrine goto error; 2218373020dSJacques Vidrine } 2228373020dSJacques Vidrine } 2238373020dSJacques Vidrine } 2248373020dSJacques Vidrine 2255e9cd1aeSAssar Westerlund krb5_warnx (context, "connection from %s", s->name); 226b528cefcSMark Murray 227b528cefcSMark Murray s->version = 0; 2288373020dSJacques Vidrine s->flags = 0; 2298373020dSJacques Vidrine slave_seen(s); 230b528cefcSMark Murray s->next = *root; 231b528cefcSMark Murray *root = s; 232b528cefcSMark Murray return; 233b528cefcSMark Murray error: 2348373020dSJacques Vidrine remove_slave(context, s, root); 235b528cefcSMark Murray } 236b528cefcSMark Murray 2375e9cd1aeSAssar Westerlund struct prop_context { 2385e9cd1aeSAssar Westerlund krb5_auth_context auth_context; 2395e9cd1aeSAssar Westerlund int fd; 2405e9cd1aeSAssar Westerlund }; 2415e9cd1aeSAssar Westerlund 242b528cefcSMark Murray static int 2435e9cd1aeSAssar Westerlund prop_one (krb5_context context, HDB *db, hdb_entry *entry, void *v) 244b528cefcSMark Murray { 2455e9cd1aeSAssar Westerlund krb5_error_code ret; 2465e9cd1aeSAssar Westerlund krb5_data data; 2475e9cd1aeSAssar Westerlund struct slave *slave = (struct slave *)v; 2485e9cd1aeSAssar Westerlund 2495e9cd1aeSAssar Westerlund ret = hdb_entry2value (context, entry, &data); 2505e9cd1aeSAssar Westerlund if (ret) 2515e9cd1aeSAssar Westerlund return ret; 2525e9cd1aeSAssar Westerlund ret = krb5_data_realloc (&data, data.length + 4); 2535e9cd1aeSAssar Westerlund if (ret) { 2545e9cd1aeSAssar Westerlund krb5_data_free (&data); 2555e9cd1aeSAssar Westerlund return ret; 2565e9cd1aeSAssar Westerlund } 2575e9cd1aeSAssar Westerlund memmove ((char *)data.data + 4, data.data, data.length - 4); 2585e9cd1aeSAssar Westerlund _krb5_put_int (data.data, ONE_PRINC, 4); 2595e9cd1aeSAssar Westerlund 2605e9cd1aeSAssar Westerlund ret = krb5_write_priv_message (context, slave->ac, &slave->fd, &data); 2615e9cd1aeSAssar Westerlund krb5_data_free (&data); 2625e9cd1aeSAssar Westerlund return ret; 2635e9cd1aeSAssar Westerlund } 2645e9cd1aeSAssar Westerlund 2655e9cd1aeSAssar Westerlund static int 2665e9cd1aeSAssar Westerlund send_complete (krb5_context context, slave *s, 2675e9cd1aeSAssar Westerlund const char *database, u_int32_t current_version) 2685e9cd1aeSAssar Westerlund { 2695e9cd1aeSAssar Westerlund krb5_error_code ret; 2705e9cd1aeSAssar Westerlund HDB *db; 2715e9cd1aeSAssar Westerlund krb5_data data; 2725e9cd1aeSAssar Westerlund char buf[8]; 2735e9cd1aeSAssar Westerlund 2745e9cd1aeSAssar Westerlund ret = hdb_create (context, &db, database); 2755e9cd1aeSAssar Westerlund if (ret) 2765e9cd1aeSAssar Westerlund krb5_err (context, 1, ret, "hdb_create: %s", database); 2775e9cd1aeSAssar Westerlund ret = db->open (context, db, O_RDONLY, 0); 2785e9cd1aeSAssar Westerlund if (ret) 2795e9cd1aeSAssar Westerlund krb5_err (context, 1, ret, "db->open"); 2805e9cd1aeSAssar Westerlund 2815e9cd1aeSAssar Westerlund _krb5_put_int(buf, TELL_YOU_EVERYTHING, 4); 2825e9cd1aeSAssar Westerlund 2835e9cd1aeSAssar Westerlund data.data = buf; 2845e9cd1aeSAssar Westerlund data.length = 4; 2855e9cd1aeSAssar Westerlund 2865e9cd1aeSAssar Westerlund ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); 2875e9cd1aeSAssar Westerlund 2888373020dSJacques Vidrine if (ret) { 2898373020dSJacques Vidrine krb5_warn (context, ret, "krb5_write_priv_message"); 2908373020dSJacques Vidrine slave_dead(s); 2918373020dSJacques Vidrine return ret; 2928373020dSJacques Vidrine } 2935e9cd1aeSAssar Westerlund 2945e9cd1aeSAssar Westerlund ret = hdb_foreach (context, db, 0, prop_one, s); 2958373020dSJacques Vidrine if (ret) { 2968373020dSJacques Vidrine krb5_warn (context, ret, "hdb_foreach"); 2978373020dSJacques Vidrine slave_dead(s); 2988373020dSJacques Vidrine return ret; 2998373020dSJacques Vidrine } 3005e9cd1aeSAssar Westerlund 3015e9cd1aeSAssar Westerlund _krb5_put_int (buf, NOW_YOU_HAVE, 4); 3025e9cd1aeSAssar Westerlund _krb5_put_int (buf + 4, current_version, 4); 3035e9cd1aeSAssar Westerlund data.length = 8; 3045e9cd1aeSAssar Westerlund 3058373020dSJacques Vidrine s->version = current_version; 3065e9cd1aeSAssar Westerlund 3078373020dSJacques Vidrine ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); 3088373020dSJacques Vidrine if (ret) { 3098373020dSJacques Vidrine slave_dead(s); 3108373020dSJacques Vidrine krb5_warn (context, ret, "krb5_write_priv_message"); 3118373020dSJacques Vidrine return ret; 3128373020dSJacques Vidrine } 3138373020dSJacques Vidrine 3148373020dSJacques Vidrine slave_seen(s); 3155e9cd1aeSAssar Westerlund 3165e9cd1aeSAssar Westerlund return 0; 317b528cefcSMark Murray } 318b528cefcSMark Murray 319b528cefcSMark Murray static int 320b528cefcSMark Murray send_diffs (krb5_context context, slave *s, int log_fd, 3215e9cd1aeSAssar Westerlund const char *database, u_int32_t current_version) 322b528cefcSMark Murray { 3235e9cd1aeSAssar Westerlund krb5_storage *sp; 324b528cefcSMark Murray u_int32_t ver; 325b528cefcSMark Murray time_t timestamp; 326b528cefcSMark Murray enum kadm_ops op; 327b528cefcSMark Murray u_int32_t len; 328b528cefcSMark Murray off_t right, left; 329b528cefcSMark Murray krb5_data data; 330b528cefcSMark Murray int ret = 0; 331b528cefcSMark Murray 332b528cefcSMark Murray if (s->version == current_version) 333b528cefcSMark Murray return 0; 334b528cefcSMark Murray 3358373020dSJacques Vidrine if (s->flags & SLAVE_F_DEAD) 3368373020dSJacques Vidrine return 0; 3378373020dSJacques Vidrine 338b528cefcSMark Murray sp = kadm5_log_goto_end (log_fd); 3398373020dSJacques Vidrine right = krb5_storage_seek(sp, 0, SEEK_CUR); 340b528cefcSMark Murray for (;;) { 341b528cefcSMark Murray if (kadm5_log_previous (sp, &ver, ×tamp, &op, &len)) 342b528cefcSMark Murray abort (); 3438373020dSJacques Vidrine left = krb5_storage_seek(sp, -16, SEEK_CUR); 344b528cefcSMark Murray if (ver == s->version) 345b528cefcSMark Murray return 0; 346b528cefcSMark Murray if (ver == s->version + 1) 347b528cefcSMark Murray break; 348b528cefcSMark Murray if (left == 0) 3495e9cd1aeSAssar Westerlund return send_complete (context, s, database, current_version); 350b528cefcSMark Murray } 351b528cefcSMark Murray krb5_data_alloc (&data, right - left + 4); 3528373020dSJacques Vidrine krb5_storage_read (sp, (char *)data.data + 4, data.length - 4); 353b528cefcSMark Murray krb5_storage_free(sp); 354b528cefcSMark Murray 355b528cefcSMark Murray _krb5_put_int(data.data, FOR_YOU, 4); 356b528cefcSMark Murray 3575e9cd1aeSAssar Westerlund ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); 3588373020dSJacques Vidrine krb5_data_free(&data); 359b528cefcSMark Murray 360b528cefcSMark Murray if (ret) { 3615e9cd1aeSAssar Westerlund krb5_warn (context, ret, "krb5_write_priv_message"); 3628373020dSJacques Vidrine slave_dead(s); 363b528cefcSMark Murray return 1; 364b528cefcSMark Murray } 3658373020dSJacques Vidrine slave_seen(s); 3668373020dSJacques Vidrine 367b528cefcSMark Murray return 0; 368b528cefcSMark Murray } 369b528cefcSMark Murray 370b528cefcSMark Murray static int 371b528cefcSMark Murray process_msg (krb5_context context, slave *s, int log_fd, 3725e9cd1aeSAssar Westerlund const char *database, u_int32_t current_version) 373b528cefcSMark Murray { 374b528cefcSMark Murray int ret = 0; 3755e9cd1aeSAssar Westerlund krb5_data out; 376b528cefcSMark Murray krb5_storage *sp; 377b528cefcSMark Murray int32_t tmp; 378b528cefcSMark Murray 3795e9cd1aeSAssar Westerlund ret = krb5_read_priv_message(context, s->ac, &s->fd, &out); 380b528cefcSMark Murray if(ret) { 3815e9cd1aeSAssar Westerlund krb5_warn (context, ret, "error reading message from %s", s->name); 382b528cefcSMark Murray return 1; 383b528cefcSMark Murray } 384b528cefcSMark Murray 385b528cefcSMark Murray sp = krb5_storage_from_mem (out.data, out.length); 386b528cefcSMark Murray krb5_ret_int32 (sp, &tmp); 387b528cefcSMark Murray switch (tmp) { 388b528cefcSMark Murray case I_HAVE : 389b528cefcSMark Murray krb5_ret_int32 (sp, &tmp); 390b528cefcSMark Murray s->version = tmp; 3915e9cd1aeSAssar Westerlund ret = send_diffs (context, s, log_fd, database, current_version); 392b528cefcSMark Murray break; 393b528cefcSMark Murray case FOR_YOU : 394b528cefcSMark Murray default : 395b528cefcSMark Murray krb5_warnx (context, "Ignoring command %d", tmp); 396b528cefcSMark Murray break; 397b528cefcSMark Murray } 398b528cefcSMark Murray 399b528cefcSMark Murray krb5_data_free (&out); 4008373020dSJacques Vidrine 4018373020dSJacques Vidrine slave_seen(s); 4028373020dSJacques Vidrine 403b528cefcSMark Murray return ret; 404b528cefcSMark Murray } 405b528cefcSMark Murray 4068373020dSJacques Vidrine #define SLAVE_NAME "Name" 4078373020dSJacques Vidrine #define SLAVE_ADDRESS "Address" 4088373020dSJacques Vidrine #define SLAVE_VERSION "Version" 4098373020dSJacques Vidrine #define SLAVE_STATUS "Status" 4108373020dSJacques Vidrine #define SLAVE_SEEN "Last Seen" 4118373020dSJacques Vidrine 4128373020dSJacques Vidrine static void 4138373020dSJacques Vidrine write_stats(krb5_context context, slave *slaves, u_int32_t current_version) 4148373020dSJacques Vidrine { 415bbd80c28SJacques Vidrine char str[100]; 4168373020dSJacques Vidrine rtbl_t tbl; 4178373020dSJacques Vidrine time_t t = time(NULL); 4188373020dSJacques Vidrine FILE *fp; 4198373020dSJacques Vidrine 420bbd80c28SJacques Vidrine fp = fopen(slave_stats_file, "w"); 4218373020dSJacques Vidrine if (fp == NULL) 4228373020dSJacques Vidrine return; 4238373020dSJacques Vidrine 4248373020dSJacques Vidrine strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", 4258373020dSJacques Vidrine localtime(&t)); 4268373020dSJacques Vidrine fprintf(fp, "Status for slaves, last updated: %s\n\n", str); 4278373020dSJacques Vidrine 4288373020dSJacques Vidrine fprintf(fp, "Master version: %lu\n\n", (unsigned long)current_version); 4298373020dSJacques Vidrine 4308373020dSJacques Vidrine tbl = rtbl_create(); 4318373020dSJacques Vidrine if (tbl == NULL) { 4328373020dSJacques Vidrine fclose(fp); 4338373020dSJacques Vidrine return; 4348373020dSJacques Vidrine } 4358373020dSJacques Vidrine 4368373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_NAME, 0); 4378373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_ADDRESS, 0); 4388373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_VERSION, RTBL_ALIGN_RIGHT); 4398373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_STATUS, 0); 4408373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_SEEN, 0); 4418373020dSJacques Vidrine 4428373020dSJacques Vidrine rtbl_set_prefix(tbl, " "); 4438373020dSJacques Vidrine rtbl_set_column_prefix(tbl, SLAVE_NAME, ""); 4448373020dSJacques Vidrine 4458373020dSJacques Vidrine while (slaves) { 4468373020dSJacques Vidrine krb5_address addr; 4478373020dSJacques Vidrine krb5_error_code ret; 4488373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_NAME, slaves->name); 4498373020dSJacques Vidrine ret = krb5_sockaddr2address (context, 4508373020dSJacques Vidrine (struct sockaddr*)&slaves->addr, &addr); 4518373020dSJacques Vidrine if(ret == 0) { 4528373020dSJacques Vidrine krb5_print_address(&addr, str, sizeof(str), NULL); 4538373020dSJacques Vidrine krb5_free_address(context, &addr); 4548373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_ADDRESS, str); 4558373020dSJacques Vidrine } else 4568373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_ADDRESS, "<unknown>"); 4578373020dSJacques Vidrine 4588373020dSJacques Vidrine snprintf(str, sizeof(str), "%u", (unsigned)slaves->version); 4598373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_VERSION, str); 4608373020dSJacques Vidrine 4618373020dSJacques Vidrine if (slaves->flags & SLAVE_F_DEAD) 4628373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_STATUS, "Down"); 4638373020dSJacques Vidrine else 4648373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_STATUS, "Up"); 4658373020dSJacques Vidrine 466bbd80c28SJacques Vidrine if (strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", 467bbd80c28SJacques Vidrine localtime(&slaves->seen)) == 0) 468bbd80c28SJacques Vidrine strlcpy(str, "Unknown time", sizeof(str)); 4698373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_SEEN, str); 4708373020dSJacques Vidrine 4718373020dSJacques Vidrine slaves = slaves->next; 4728373020dSJacques Vidrine } 4738373020dSJacques Vidrine 4748373020dSJacques Vidrine rtbl_format(tbl, fp); 4758373020dSJacques Vidrine rtbl_destroy(tbl); 4768373020dSJacques Vidrine 4778373020dSJacques Vidrine fclose(fp); 4788373020dSJacques Vidrine } 4798373020dSJacques Vidrine 4808373020dSJacques Vidrine 4815e9cd1aeSAssar Westerlund static char *realm; 4825e9cd1aeSAssar Westerlund static int version_flag; 4835e9cd1aeSAssar Westerlund static int help_flag; 4845e9cd1aeSAssar Westerlund static char *keytab_str = "HDB:"; 4855e9cd1aeSAssar Westerlund static char *database; 4865e9cd1aeSAssar Westerlund 4875e9cd1aeSAssar Westerlund static struct getargs args[] = { 488b528cefcSMark Murray { "realm", 'r', arg_string, &realm }, 4895e9cd1aeSAssar Westerlund { "keytab", 'k', arg_string, &keytab_str, 4905e9cd1aeSAssar Westerlund "keytab to get authentication from", "kspec" }, 4915e9cd1aeSAssar Westerlund { "database", 'd', arg_string, &database, "database", "file"}, 492bbd80c28SJacques Vidrine { "slave-stats-file", 0, arg_string, &slave_stats_file, "file"}, 493b528cefcSMark Murray { "version", 0, arg_flag, &version_flag }, 494b528cefcSMark Murray { "help", 0, arg_flag, &help_flag } 495b528cefcSMark Murray }; 4965e9cd1aeSAssar Westerlund static int num_args = sizeof(args) / sizeof(args[0]); 497b528cefcSMark Murray 498b528cefcSMark Murray int 499b528cefcSMark Murray main(int argc, char **argv) 500b528cefcSMark Murray { 501b528cefcSMark Murray krb5_error_code ret; 502b528cefcSMark Murray krb5_context context; 503b528cefcSMark Murray void *kadm_handle; 504b528cefcSMark Murray kadm5_server_context *server_context; 505b528cefcSMark Murray kadm5_config_params conf; 506b528cefcSMark Murray int signal_fd, listen_fd; 507b528cefcSMark Murray int log_fd; 508b528cefcSMark Murray slave *slaves = NULL; 509b528cefcSMark Murray u_int32_t current_version, old_version = 0; 5105e9cd1aeSAssar Westerlund krb5_keytab keytab; 511b528cefcSMark Murray int optind; 512b528cefcSMark Murray 513b528cefcSMark Murray optind = krb5_program_setup(&context, argc, argv, args, num_args, NULL); 514b528cefcSMark Murray 515b528cefcSMark Murray if(help_flag) 516b528cefcSMark Murray krb5_std_usage(0, args, num_args); 517b528cefcSMark Murray if(version_flag) { 518b528cefcSMark Murray print_version(NULL); 519b528cefcSMark Murray exit(0); 520b528cefcSMark Murray } 521b528cefcSMark Murray 5224137ff4cSJacques Vidrine pidfile (NULL); 5235e9cd1aeSAssar Westerlund krb5_openlog (context, "ipropd-master", &log_facility); 5245e9cd1aeSAssar Westerlund krb5_set_warn_dest(context, log_facility); 5255e9cd1aeSAssar Westerlund 5265e9cd1aeSAssar Westerlund ret = krb5_kt_register(context, &hdb_kt_ops); 5275e9cd1aeSAssar Westerlund if(ret) 5285e9cd1aeSAssar Westerlund krb5_err(context, 1, ret, "krb5_kt_register"); 5295e9cd1aeSAssar Westerlund 5305e9cd1aeSAssar Westerlund ret = krb5_kt_resolve(context, keytab_str, &keytab); 5315e9cd1aeSAssar Westerlund if(ret) 5325e9cd1aeSAssar Westerlund krb5_err(context, 1, ret, "krb5_kt_resolve: %s", keytab_str); 5335e9cd1aeSAssar Westerlund 534b528cefcSMark Murray memset(&conf, 0, sizeof(conf)); 535b528cefcSMark Murray if(realm) { 536b528cefcSMark Murray conf.mask |= KADM5_CONFIG_REALM; 537b528cefcSMark Murray conf.realm = realm; 538b528cefcSMark Murray } 5395e9cd1aeSAssar Westerlund ret = kadm5_init_with_skey_ctx (context, 540b528cefcSMark Murray KADM5_ADMIN_SERVICE, 541b528cefcSMark Murray NULL, 542b528cefcSMark Murray KADM5_ADMIN_SERVICE, 543b528cefcSMark Murray &conf, 0, 0, 544b528cefcSMark Murray &kadm_handle); 545b528cefcSMark Murray if (ret) 546b528cefcSMark Murray krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); 547b528cefcSMark Murray 548b528cefcSMark Murray server_context = (kadm5_server_context *)kadm_handle; 549b528cefcSMark Murray 550b528cefcSMark Murray log_fd = open (server_context->log_context.log_file, O_RDONLY, 0); 551b528cefcSMark Murray if (log_fd < 0) 552b528cefcSMark Murray krb5_err (context, 1, errno, "open %s", 553b528cefcSMark Murray server_context->log_context.log_file); 554b528cefcSMark Murray 555b528cefcSMark Murray signal_fd = make_signal_socket (context); 556b528cefcSMark Murray listen_fd = make_listen_socket (context); 557b528cefcSMark Murray 5585e9cd1aeSAssar Westerlund signal (SIGPIPE, SIG_IGN); 5595e9cd1aeSAssar Westerlund 560b528cefcSMark Murray for (;;) { 561b528cefcSMark Murray slave *p; 562b528cefcSMark Murray fd_set readset; 563b528cefcSMark Murray int max_fd = 0; 564b528cefcSMark Murray struct timeval to = {30, 0}; 565b528cefcSMark Murray u_int32_t vers; 566b528cefcSMark Murray 5675e9cd1aeSAssar Westerlund if (signal_fd >= FD_SETSIZE || listen_fd >= FD_SETSIZE) 5685e9cd1aeSAssar Westerlund krb5_errx (context, 1, "fd too large"); 5695e9cd1aeSAssar Westerlund 570b528cefcSMark Murray FD_ZERO(&readset); 571b528cefcSMark Murray FD_SET(signal_fd, &readset); 572b528cefcSMark Murray max_fd = max(max_fd, signal_fd); 573b528cefcSMark Murray FD_SET(listen_fd, &readset); 574b528cefcSMark Murray max_fd = max(max_fd, listen_fd); 575b528cefcSMark Murray 576b528cefcSMark Murray for (p = slaves; p != NULL; p = p->next) { 577bbd80c28SJacques Vidrine if (p->flags & SLAVE_F_DEAD) 578bbd80c28SJacques Vidrine continue; 579b528cefcSMark Murray FD_SET(p->fd, &readset); 580b528cefcSMark Murray max_fd = max(max_fd, p->fd); 581b528cefcSMark Murray } 582b528cefcSMark Murray 583b528cefcSMark Murray ret = select (max_fd + 1, 584b528cefcSMark Murray &readset, NULL, NULL, &to); 585b528cefcSMark Murray if (ret < 0) { 586b528cefcSMark Murray if (errno == EINTR) 587b528cefcSMark Murray continue; 588b528cefcSMark Murray else 589b528cefcSMark Murray krb5_err (context, 1, errno, "select"); 590b528cefcSMark Murray } 591b528cefcSMark Murray 592b528cefcSMark Murray if (ret == 0) { 593b528cefcSMark Murray old_version = current_version; 5945e9cd1aeSAssar Westerlund kadm5_log_get_version_fd (log_fd, ¤t_version); 595b528cefcSMark Murray 596b528cefcSMark Murray if (current_version > old_version) 597bbd80c28SJacques Vidrine for (p = slaves; p != NULL; p = p->next) { 598bbd80c28SJacques Vidrine if (p->flags & SLAVE_F_DEAD) 599bbd80c28SJacques Vidrine continue; 6005e9cd1aeSAssar Westerlund send_diffs (context, p, log_fd, database, current_version); 601b528cefcSMark Murray } 602bbd80c28SJacques Vidrine } 603b528cefcSMark Murray 604b528cefcSMark Murray if (ret && FD_ISSET(signal_fd, &readset)) { 605b528cefcSMark Murray struct sockaddr_un peer_addr; 6065e9cd1aeSAssar Westerlund socklen_t peer_len = sizeof(peer_addr); 607b528cefcSMark Murray 6084137ff4cSJacques Vidrine if(recvfrom(signal_fd, (void *)&vers, sizeof(vers), 0, 609b528cefcSMark Murray (struct sockaddr *)&peer_addr, &peer_len) < 0) { 610b528cefcSMark Murray krb5_warn (context, errno, "recvfrom"); 611b528cefcSMark Murray continue; 612b528cefcSMark Murray } 613b528cefcSMark Murray --ret; 614b528cefcSMark Murray old_version = current_version; 6155e9cd1aeSAssar Westerlund kadm5_log_get_version_fd (log_fd, ¤t_version); 616b528cefcSMark Murray for (p = slaves; p != NULL; p = p->next) 6175e9cd1aeSAssar Westerlund send_diffs (context, p, log_fd, database, current_version); 618b528cefcSMark Murray } 619b528cefcSMark Murray 620bbd80c28SJacques Vidrine for(p = slaves; ret && p != NULL; p = p->next) { 621bbd80c28SJacques Vidrine if (p->flags & SLAVE_F_DEAD) 622bbd80c28SJacques Vidrine continue; 623b528cefcSMark Murray if (FD_ISSET(p->fd, &readset)) { 624adb0ddaeSAssar Westerlund --ret; 6255e9cd1aeSAssar Westerlund if(process_msg (context, p, log_fd, database, current_version)) 6268373020dSJacques Vidrine slave_dead(p); 627b528cefcSMark Murray } 628bbd80c28SJacques Vidrine } 629b528cefcSMark Murray 630b528cefcSMark Murray if (ret && FD_ISSET(listen_fd, &readset)) { 6315e9cd1aeSAssar Westerlund add_slave (context, keytab, &slaves, listen_fd); 632b528cefcSMark Murray --ret; 633b528cefcSMark Murray } 6348373020dSJacques Vidrine write_stats(context, slaves, current_version); 635b528cefcSMark Murray } 636b528cefcSMark Murray 637b528cefcSMark Murray return 0; 638b528cefcSMark Murray } 639