1b528cefcSMark Murray /* 2*ae771770SStanislav Sedov * Copyright (c) 1997 - 2008 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 375e9cd1aeSAssar Westerlund static krb5_log_facility *log_facility; 38b528cefcSMark Murray 39c19800e8SDoug Rabson const char *slave_stats_file; 40c19800e8SDoug Rabson const char *slave_time_missing = "2 min"; 41c19800e8SDoug Rabson const char *slave_time_gone = "5 min"; 42c19800e8SDoug Rabson 43c19800e8SDoug Rabson static int time_before_missing; 44c19800e8SDoug Rabson static int time_before_gone; 45c19800e8SDoug Rabson 46c19800e8SDoug Rabson const char *master_hostname; 47bbd80c28SJacques Vidrine 48*ae771770SStanislav Sedov static krb5_socket_t 49b528cefcSMark Murray make_signal_socket (krb5_context context) 50b528cefcSMark Murray { 51*ae771770SStanislav Sedov #ifndef NO_UNIX_SOCKETS 52b528cefcSMark Murray struct sockaddr_un addr; 53c19800e8SDoug Rabson const char *fn; 54*ae771770SStanislav Sedov krb5_socket_t fd; 55b528cefcSMark Murray 56c19800e8SDoug Rabson fn = kadm5_log_signal_socket(context); 57c19800e8SDoug Rabson 58b528cefcSMark Murray fd = socket (AF_UNIX, SOCK_DGRAM, 0); 59b528cefcSMark Murray if (fd < 0) 60b528cefcSMark Murray krb5_err (context, 1, errno, "socket AF_UNIX"); 61b528cefcSMark Murray memset (&addr, 0, sizeof(addr)); 62b528cefcSMark Murray addr.sun_family = AF_UNIX; 63c19800e8SDoug Rabson strlcpy (addr.sun_path, fn, sizeof(addr.sun_path)); 64b528cefcSMark Murray unlink (addr.sun_path); 65b528cefcSMark Murray if (bind (fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) 66b528cefcSMark Murray krb5_err (context, 1, errno, "bind %s", addr.sun_path); 67b528cefcSMark Murray return fd; 68*ae771770SStanislav Sedov #else 69*ae771770SStanislav Sedov struct addrinfo *ai = NULL; 70*ae771770SStanislav Sedov krb5_socket_t fd; 71*ae771770SStanislav Sedov 72*ae771770SStanislav Sedov kadm5_log_signal_socket_info(context, 1, &ai); 73*ae771770SStanislav Sedov 74*ae771770SStanislav Sedov fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 75*ae771770SStanislav Sedov if (rk_IS_BAD_SOCKET(fd)) 76*ae771770SStanislav Sedov krb5_err (context, 1, rk_SOCK_ERRNO, "socket AF=%d", ai->ai_family); 77*ae771770SStanislav Sedov 78*ae771770SStanislav Sedov if (rk_IS_SOCKET_ERROR( bind (fd, ai->ai_addr, ai->ai_addrlen) )) 79*ae771770SStanislav Sedov krb5_err (context, 1, rk_SOCK_ERRNO, "bind"); 80*ae771770SStanislav Sedov return fd; 81*ae771770SStanislav Sedov #endif 82b528cefcSMark Murray } 83b528cefcSMark Murray 84*ae771770SStanislav Sedov static krb5_socket_t 85c19800e8SDoug Rabson make_listen_socket (krb5_context context, const char *port_str) 86b528cefcSMark Murray { 87*ae771770SStanislav Sedov krb5_socket_t fd; 88b528cefcSMark Murray int one = 1; 89b528cefcSMark Murray struct sockaddr_in addr; 90b528cefcSMark Murray 91b528cefcSMark Murray fd = socket (AF_INET, SOCK_STREAM, 0); 92*ae771770SStanislav Sedov if (rk_IS_BAD_SOCKET(fd)) 93*ae771770SStanislav Sedov krb5_err (context, 1, rk_SOCK_ERRNO, "socket AF_INET"); 944137ff4cSJacques Vidrine setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); 95b528cefcSMark Murray memset (&addr, 0, sizeof(addr)); 96b528cefcSMark Murray addr.sin_family = AF_INET; 97c19800e8SDoug Rabson 98c19800e8SDoug Rabson if (port_str) { 995e9cd1aeSAssar Westerlund addr.sin_port = krb5_getportbyname (context, 100c19800e8SDoug Rabson port_str, "tcp", 101c19800e8SDoug Rabson 0); 102c19800e8SDoug Rabson if (addr.sin_port == 0) { 103c19800e8SDoug Rabson char *ptr; 104c19800e8SDoug Rabson long port; 105c19800e8SDoug Rabson 106c19800e8SDoug Rabson port = strtol (port_str, &ptr, 10); 107c19800e8SDoug Rabson if (port == 0 && ptr == port_str) 108c19800e8SDoug Rabson krb5_errx (context, 1, "bad port `%s'", port_str); 109c19800e8SDoug Rabson addr.sin_port = htons(port); 110c19800e8SDoug Rabson } 111c19800e8SDoug Rabson } else { 112c19800e8SDoug Rabson addr.sin_port = krb5_getportbyname (context, IPROP_SERVICE, 113c19800e8SDoug Rabson "tcp", IPROP_PORT); 114c19800e8SDoug Rabson } 115b528cefcSMark Murray if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) 116b528cefcSMark Murray krb5_err (context, 1, errno, "bind"); 117b528cefcSMark Murray if (listen(fd, SOMAXCONN) < 0) 118b528cefcSMark Murray krb5_err (context, 1, errno, "listen"); 119b528cefcSMark Murray return fd; 120b528cefcSMark Murray } 121b528cefcSMark Murray 122b528cefcSMark Murray struct slave { 123*ae771770SStanislav Sedov krb5_socket_t fd; 124b528cefcSMark Murray struct sockaddr_in addr; 125b528cefcSMark Murray char *name; 126b528cefcSMark Murray krb5_auth_context ac; 127c19800e8SDoug Rabson uint32_t version; 1288373020dSJacques Vidrine time_t seen; 1298373020dSJacques Vidrine unsigned long flags; 1308373020dSJacques Vidrine #define SLAVE_F_DEAD 0x1 131c19800e8SDoug Rabson #define SLAVE_F_AYT 0x2 132b528cefcSMark Murray struct slave *next; 133b528cefcSMark Murray }; 134b528cefcSMark Murray 135b528cefcSMark Murray typedef struct slave slave; 136b528cefcSMark Murray 137b528cefcSMark Murray static int 138b528cefcSMark Murray check_acl (krb5_context context, const char *name) 139b528cefcSMark Murray { 140c19800e8SDoug Rabson const char *fn; 141b528cefcSMark Murray FILE *fp; 142b528cefcSMark Murray char buf[256]; 143b528cefcSMark Murray int ret = 1; 144*ae771770SStanislav Sedov char *slavefile = NULL; 145b528cefcSMark Murray 146*ae771770SStanislav Sedov if (asprintf(&slavefile, "%s/slaves", hdb_db_dir(context)) == -1 147*ae771770SStanislav Sedov || slavefile == NULL) 148*ae771770SStanislav Sedov errx(1, "out of memory"); 149c19800e8SDoug Rabson 150c19800e8SDoug Rabson fn = krb5_config_get_string_default(context, 151c19800e8SDoug Rabson NULL, 152c19800e8SDoug Rabson slavefile, 153c19800e8SDoug Rabson "kdc", 154c19800e8SDoug Rabson "iprop-acl", 155c19800e8SDoug Rabson NULL); 156c19800e8SDoug Rabson 157c19800e8SDoug Rabson fp = fopen (fn, "r"); 158c19800e8SDoug Rabson free(slavefile); 159b528cefcSMark Murray if (fp == NULL) 160b528cefcSMark Murray return 1; 161b528cefcSMark Murray while (fgets(buf, sizeof(buf), fp) != NULL) { 162c19800e8SDoug Rabson buf[strcspn(buf, "\r\n")] = '\0'; 163b528cefcSMark Murray if (strcmp (buf, name) == 0) { 164b528cefcSMark Murray ret = 0; 165b528cefcSMark Murray break; 166b528cefcSMark Murray } 167b528cefcSMark Murray } 168b528cefcSMark Murray fclose (fp); 169b528cefcSMark Murray return ret; 170b528cefcSMark Murray } 171b528cefcSMark Murray 172b528cefcSMark Murray static void 1738373020dSJacques Vidrine slave_seen(slave *s) 1748373020dSJacques Vidrine { 175c19800e8SDoug Rabson s->flags &= ~SLAVE_F_AYT; 1768373020dSJacques Vidrine s->seen = time(NULL); 1778373020dSJacques Vidrine } 1788373020dSJacques Vidrine 179c19800e8SDoug Rabson static int 180c19800e8SDoug Rabson slave_missing_p (slave *s) 1818373020dSJacques Vidrine { 182c19800e8SDoug Rabson if (time(NULL) > s->seen + time_before_missing) 183c19800e8SDoug Rabson return 1; 184c19800e8SDoug Rabson return 0; 185c19800e8SDoug Rabson } 186c19800e8SDoug Rabson 187c19800e8SDoug Rabson static int 188c19800e8SDoug Rabson slave_gone_p (slave *s) 189c19800e8SDoug Rabson { 190c19800e8SDoug Rabson if (time(NULL) > s->seen + time_before_gone) 191c19800e8SDoug Rabson return 1; 192c19800e8SDoug Rabson return 0; 193c19800e8SDoug Rabson } 194c19800e8SDoug Rabson 195c19800e8SDoug Rabson static void 196c19800e8SDoug Rabson slave_dead(krb5_context context, slave *s) 197c19800e8SDoug Rabson { 198c19800e8SDoug Rabson krb5_warnx(context, "slave %s dead", s->name); 199c19800e8SDoug Rabson 200*ae771770SStanislav Sedov if (!rk_IS_BAD_SOCKET(s->fd)) { 201*ae771770SStanislav Sedov rk_closesocket (s->fd); 202*ae771770SStanislav Sedov s->fd = rk_INVALID_SOCKET; 203bbd80c28SJacques Vidrine } 2048373020dSJacques Vidrine s->flags |= SLAVE_F_DEAD; 2058373020dSJacques Vidrine slave_seen(s); 2068373020dSJacques Vidrine } 2078373020dSJacques Vidrine 2088373020dSJacques Vidrine static void 2098373020dSJacques Vidrine remove_slave (krb5_context context, slave *s, slave **root) 2108373020dSJacques Vidrine { 2118373020dSJacques Vidrine slave **p; 2128373020dSJacques Vidrine 213*ae771770SStanislav Sedov if (!rk_IS_BAD_SOCKET(s->fd)) 214*ae771770SStanislav Sedov rk_closesocket (s->fd); 2158373020dSJacques Vidrine if (s->name) 2168373020dSJacques Vidrine free (s->name); 2178373020dSJacques Vidrine if (s->ac) 2188373020dSJacques Vidrine krb5_auth_con_free (context, s->ac); 2198373020dSJacques Vidrine 2208373020dSJacques Vidrine for (p = root; *p; p = &(*p)->next) 2218373020dSJacques Vidrine if (*p == s) { 2228373020dSJacques Vidrine *p = s->next; 2238373020dSJacques Vidrine break; 2248373020dSJacques Vidrine } 2258373020dSJacques Vidrine free (s); 2268373020dSJacques Vidrine } 2278373020dSJacques Vidrine 2288373020dSJacques Vidrine static void 229*ae771770SStanislav Sedov add_slave (krb5_context context, krb5_keytab keytab, slave **root, 230*ae771770SStanislav Sedov krb5_socket_t fd) 231b528cefcSMark Murray { 232b528cefcSMark Murray krb5_principal server; 233b528cefcSMark Murray krb5_error_code ret; 234b528cefcSMark Murray slave *s; 2355e9cd1aeSAssar Westerlund socklen_t addr_len; 236b528cefcSMark Murray krb5_ticket *ticket = NULL; 237b528cefcSMark Murray char hostname[128]; 238b528cefcSMark Murray 239b528cefcSMark Murray s = malloc(sizeof(*s)); 240b528cefcSMark Murray if (s == NULL) { 241b528cefcSMark Murray krb5_warnx (context, "add_slave: no memory"); 242b528cefcSMark Murray return; 243b528cefcSMark Murray } 244b528cefcSMark Murray s->name = NULL; 245b528cefcSMark Murray s->ac = NULL; 246b528cefcSMark Murray 247b528cefcSMark Murray addr_len = sizeof(s->addr); 248b528cefcSMark Murray s->fd = accept (fd, (struct sockaddr *)&s->addr, &addr_len); 249*ae771770SStanislav Sedov if (rk_IS_BAD_SOCKET(s->fd)) { 250*ae771770SStanislav Sedov krb5_warn (context, rk_SOCK_ERRNO, "accept"); 251b528cefcSMark Murray goto error; 252b528cefcSMark Murray } 253c19800e8SDoug Rabson if (master_hostname) 254c19800e8SDoug Rabson strlcpy(hostname, master_hostname, sizeof(hostname)); 255c19800e8SDoug Rabson else 256b528cefcSMark Murray gethostname(hostname, sizeof(hostname)); 257c19800e8SDoug Rabson 258b528cefcSMark Murray ret = krb5_sname_to_principal (context, hostname, IPROP_NAME, 259b528cefcSMark Murray KRB5_NT_SRV_HST, &server); 260b528cefcSMark Murray if (ret) { 261b528cefcSMark Murray krb5_warn (context, ret, "krb5_sname_to_principal"); 262b528cefcSMark Murray goto error; 263b528cefcSMark Murray } 264b528cefcSMark Murray 265b528cefcSMark Murray ret = krb5_recvauth (context, &s->ac, &s->fd, 2665e9cd1aeSAssar Westerlund IPROP_VERSION, server, 0, keytab, &ticket); 267b528cefcSMark Murray krb5_free_principal (context, server); 268b528cefcSMark Murray if (ret) { 269b528cefcSMark Murray krb5_warn (context, ret, "krb5_recvauth"); 270b528cefcSMark Murray goto error; 271b528cefcSMark Murray } 272b528cefcSMark Murray ret = krb5_unparse_name (context, ticket->client, &s->name); 273*ae771770SStanislav Sedov krb5_free_ticket (context, ticket); 274b528cefcSMark Murray if (ret) { 275b528cefcSMark Murray krb5_warn (context, ret, "krb5_unparse_name"); 276b528cefcSMark Murray goto error; 277b528cefcSMark Murray } 278b528cefcSMark Murray if (check_acl (context, s->name)) { 279b528cefcSMark Murray krb5_warnx (context, "%s not in acl", s->name); 280b528cefcSMark Murray goto error; 281b528cefcSMark Murray } 2828373020dSJacques Vidrine 2838373020dSJacques Vidrine { 2848373020dSJacques Vidrine slave *l = *root; 2858373020dSJacques Vidrine 2868373020dSJacques Vidrine while (l) { 2878373020dSJacques Vidrine if (strcmp(l->name, s->name) == 0) 2888373020dSJacques Vidrine break; 2898373020dSJacques Vidrine l = l->next; 2908373020dSJacques Vidrine } 2918373020dSJacques Vidrine if (l) { 2928373020dSJacques Vidrine if (l->flags & SLAVE_F_DEAD) { 2938373020dSJacques Vidrine remove_slave(context, l, root); 2948373020dSJacques Vidrine } else { 2958373020dSJacques Vidrine krb5_warnx (context, "second connection from %s", s->name); 2968373020dSJacques Vidrine goto error; 2978373020dSJacques Vidrine } 2988373020dSJacques Vidrine } 2998373020dSJacques Vidrine } 3008373020dSJacques Vidrine 3015e9cd1aeSAssar Westerlund krb5_warnx (context, "connection from %s", s->name); 302b528cefcSMark Murray 303b528cefcSMark Murray s->version = 0; 3048373020dSJacques Vidrine s->flags = 0; 3058373020dSJacques Vidrine slave_seen(s); 306b528cefcSMark Murray s->next = *root; 307b528cefcSMark Murray *root = s; 308b528cefcSMark Murray return; 309b528cefcSMark Murray error: 3108373020dSJacques Vidrine remove_slave(context, s, root); 311b528cefcSMark Murray } 312b528cefcSMark Murray 3135e9cd1aeSAssar Westerlund struct prop_context { 3145e9cd1aeSAssar Westerlund krb5_auth_context auth_context; 315*ae771770SStanislav Sedov krb5_socket_t fd; 3165e9cd1aeSAssar Westerlund }; 3175e9cd1aeSAssar Westerlund 318b528cefcSMark Murray static int 319c19800e8SDoug Rabson prop_one (krb5_context context, HDB *db, hdb_entry_ex *entry, void *v) 320b528cefcSMark Murray { 3215e9cd1aeSAssar Westerlund krb5_error_code ret; 322c19800e8SDoug Rabson krb5_storage *sp; 3235e9cd1aeSAssar Westerlund krb5_data data; 324c19800e8SDoug Rabson struct slave *s = (struct slave *)v; 3255e9cd1aeSAssar Westerlund 326c19800e8SDoug Rabson ret = hdb_entry2value (context, &entry->entry, &data); 3275e9cd1aeSAssar Westerlund if (ret) 3285e9cd1aeSAssar Westerlund return ret; 3295e9cd1aeSAssar Westerlund ret = krb5_data_realloc (&data, data.length + 4); 3305e9cd1aeSAssar Westerlund if (ret) { 3315e9cd1aeSAssar Westerlund krb5_data_free (&data); 3325e9cd1aeSAssar Westerlund return ret; 3335e9cd1aeSAssar Westerlund } 3345e9cd1aeSAssar Westerlund memmove ((char *)data.data + 4, data.data, data.length - 4); 335c19800e8SDoug Rabson sp = krb5_storage_from_data(&data); 336c19800e8SDoug Rabson if (sp == NULL) { 337c19800e8SDoug Rabson krb5_data_free (&data); 338c19800e8SDoug Rabson return ENOMEM; 339c19800e8SDoug Rabson } 340c19800e8SDoug Rabson krb5_store_int32(sp, ONE_PRINC); 341c19800e8SDoug Rabson krb5_storage_free(sp); 3425e9cd1aeSAssar Westerlund 343c19800e8SDoug Rabson ret = krb5_write_priv_message (context, s->ac, &s->fd, &data); 3445e9cd1aeSAssar Westerlund krb5_data_free (&data); 3455e9cd1aeSAssar Westerlund return ret; 3465e9cd1aeSAssar Westerlund } 3475e9cd1aeSAssar Westerlund 3485e9cd1aeSAssar Westerlund static int 3495e9cd1aeSAssar Westerlund send_complete (krb5_context context, slave *s, 350c19800e8SDoug Rabson const char *database, uint32_t current_version) 3515e9cd1aeSAssar Westerlund { 3525e9cd1aeSAssar Westerlund krb5_error_code ret; 353c19800e8SDoug Rabson krb5_storage *sp; 3545e9cd1aeSAssar Westerlund HDB *db; 3555e9cd1aeSAssar Westerlund krb5_data data; 3565e9cd1aeSAssar Westerlund char buf[8]; 3575e9cd1aeSAssar Westerlund 3585e9cd1aeSAssar Westerlund ret = hdb_create (context, &db, database); 3595e9cd1aeSAssar Westerlund if (ret) 3605e9cd1aeSAssar Westerlund krb5_err (context, 1, ret, "hdb_create: %s", database); 361c19800e8SDoug Rabson ret = db->hdb_open (context, db, O_RDONLY, 0); 3625e9cd1aeSAssar Westerlund if (ret) 3635e9cd1aeSAssar Westerlund krb5_err (context, 1, ret, "db->open"); 3645e9cd1aeSAssar Westerlund 365c19800e8SDoug Rabson sp = krb5_storage_from_mem (buf, 4); 366c19800e8SDoug Rabson if (sp == NULL) 367c19800e8SDoug Rabson krb5_errx (context, 1, "krb5_storage_from_mem"); 368c19800e8SDoug Rabson krb5_store_int32 (sp, TELL_YOU_EVERYTHING); 369c19800e8SDoug Rabson krb5_storage_free (sp); 3705e9cd1aeSAssar Westerlund 3715e9cd1aeSAssar Westerlund data.data = buf; 3725e9cd1aeSAssar Westerlund data.length = 4; 3735e9cd1aeSAssar Westerlund 3745e9cd1aeSAssar Westerlund ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); 3755e9cd1aeSAssar Westerlund 3768373020dSJacques Vidrine if (ret) { 3778373020dSJacques Vidrine krb5_warn (context, ret, "krb5_write_priv_message"); 378c19800e8SDoug Rabson slave_dead(context, s); 3798373020dSJacques Vidrine return ret; 3808373020dSJacques Vidrine } 3815e9cd1aeSAssar Westerlund 382*ae771770SStanislav Sedov ret = hdb_foreach (context, db, HDB_F_ADMIN_DATA, prop_one, s); 3838373020dSJacques Vidrine if (ret) { 3848373020dSJacques Vidrine krb5_warn (context, ret, "hdb_foreach"); 385c19800e8SDoug Rabson slave_dead(context, s); 3868373020dSJacques Vidrine return ret; 3878373020dSJacques Vidrine } 3885e9cd1aeSAssar Westerlund 389c19800e8SDoug Rabson (*db->hdb_close)(context, db); 390c19800e8SDoug Rabson (*db->hdb_destroy)(context, db); 391c19800e8SDoug Rabson 392c19800e8SDoug Rabson sp = krb5_storage_from_mem (buf, 8); 393c19800e8SDoug Rabson if (sp == NULL) 394c19800e8SDoug Rabson krb5_errx (context, 1, "krb5_storage_from_mem"); 395c19800e8SDoug Rabson krb5_store_int32 (sp, NOW_YOU_HAVE); 396c19800e8SDoug Rabson krb5_store_int32 (sp, current_version); 397c19800e8SDoug Rabson krb5_storage_free (sp); 398c19800e8SDoug Rabson 3995e9cd1aeSAssar Westerlund data.length = 8; 4005e9cd1aeSAssar Westerlund 4018373020dSJacques Vidrine s->version = current_version; 4025e9cd1aeSAssar Westerlund 4038373020dSJacques Vidrine ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); 4048373020dSJacques Vidrine if (ret) { 405c19800e8SDoug Rabson slave_dead(context, s); 4068373020dSJacques Vidrine krb5_warn (context, ret, "krb5_write_priv_message"); 4078373020dSJacques Vidrine return ret; 4088373020dSJacques Vidrine } 4098373020dSJacques Vidrine 4108373020dSJacques Vidrine slave_seen(s); 4115e9cd1aeSAssar Westerlund 4125e9cd1aeSAssar Westerlund return 0; 413b528cefcSMark Murray } 414b528cefcSMark Murray 415b528cefcSMark Murray static int 416c19800e8SDoug Rabson send_are_you_there (krb5_context context, slave *s) 417b528cefcSMark Murray { 4185e9cd1aeSAssar Westerlund krb5_storage *sp; 419c19800e8SDoug Rabson krb5_data data; 420c19800e8SDoug Rabson char buf[4]; 421c19800e8SDoug Rabson int ret; 422c19800e8SDoug Rabson 423c19800e8SDoug Rabson if (s->flags & (SLAVE_F_DEAD|SLAVE_F_AYT)) 424c19800e8SDoug Rabson return 0; 425c19800e8SDoug Rabson 426*ae771770SStanislav Sedov krb5_warnx(context, "slave %s missing, sending AYT", s->name); 427*ae771770SStanislav Sedov 428c19800e8SDoug Rabson s->flags |= SLAVE_F_AYT; 429c19800e8SDoug Rabson 430c19800e8SDoug Rabson data.data = buf; 431c19800e8SDoug Rabson data.length = 4; 432c19800e8SDoug Rabson 433c19800e8SDoug Rabson sp = krb5_storage_from_mem (buf, 4); 434c19800e8SDoug Rabson if (sp == NULL) { 435c19800e8SDoug Rabson krb5_warnx (context, "are_you_there: krb5_data_alloc"); 436c19800e8SDoug Rabson slave_dead(context, s); 437c19800e8SDoug Rabson return 1; 438c19800e8SDoug Rabson } 439c19800e8SDoug Rabson krb5_store_int32 (sp, ARE_YOU_THERE); 440c19800e8SDoug Rabson krb5_storage_free (sp); 441c19800e8SDoug Rabson 442c19800e8SDoug Rabson ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); 443c19800e8SDoug Rabson 444c19800e8SDoug Rabson if (ret) { 445c19800e8SDoug Rabson krb5_warn (context, ret, "are_you_there: krb5_write_priv_message"); 446c19800e8SDoug Rabson slave_dead(context, s); 447c19800e8SDoug Rabson return 1; 448c19800e8SDoug Rabson } 449c19800e8SDoug Rabson 450c19800e8SDoug Rabson return 0; 451c19800e8SDoug Rabson } 452c19800e8SDoug Rabson 453c19800e8SDoug Rabson static int 454c19800e8SDoug Rabson send_diffs (krb5_context context, slave *s, int log_fd, 455c19800e8SDoug Rabson const char *database, uint32_t current_version) 456c19800e8SDoug Rabson { 457c19800e8SDoug Rabson krb5_storage *sp; 458c19800e8SDoug Rabson uint32_t ver; 459b528cefcSMark Murray time_t timestamp; 460b528cefcSMark Murray enum kadm_ops op; 461c19800e8SDoug Rabson uint32_t len; 462b528cefcSMark Murray off_t right, left; 463b528cefcSMark Murray krb5_data data; 464b528cefcSMark Murray int ret = 0; 465b528cefcSMark Murray 466c19800e8SDoug Rabson if (s->version == current_version) { 467c19800e8SDoug Rabson krb5_warnx(context, "slave %s in sync already at version %ld", 468c19800e8SDoug Rabson s->name, (long)s->version); 469b528cefcSMark Murray return 0; 470c19800e8SDoug Rabson } 471b528cefcSMark Murray 4728373020dSJacques Vidrine if (s->flags & SLAVE_F_DEAD) 4738373020dSJacques Vidrine return 0; 4748373020dSJacques Vidrine 475c19800e8SDoug Rabson /* if slave is a fresh client, starting over */ 476c19800e8SDoug Rabson if (s->version == 0) { 477c19800e8SDoug Rabson krb5_warnx(context, "sending complete log to fresh slave %s", 478c19800e8SDoug Rabson s->name); 479c19800e8SDoug Rabson return send_complete (context, s, database, current_version); 480c19800e8SDoug Rabson } 481c19800e8SDoug Rabson 482b528cefcSMark Murray sp = kadm5_log_goto_end (log_fd); 4838373020dSJacques Vidrine right = krb5_storage_seek(sp, 0, SEEK_CUR); 484b528cefcSMark Murray for (;;) { 485c19800e8SDoug Rabson ret = kadm5_log_previous (context, sp, &ver, ×tamp, &op, &len); 486c19800e8SDoug Rabson if (ret) 487c19800e8SDoug Rabson krb5_err(context, 1, ret, 488c19800e8SDoug Rabson "send_diffs: failed to find previous entry"); 4898373020dSJacques Vidrine left = krb5_storage_seek(sp, -16, SEEK_CUR); 490b528cefcSMark Murray if (ver == s->version) 491b528cefcSMark Murray return 0; 492b528cefcSMark Murray if (ver == s->version + 1) 493b528cefcSMark Murray break; 494c19800e8SDoug Rabson if (left == 0) { 495*ae771770SStanislav Sedov krb5_storage_free(sp); 496c19800e8SDoug Rabson krb5_warnx(context, 497c19800e8SDoug Rabson "slave %s (version %lu) out of sync with master " 498c19800e8SDoug Rabson "(first version in log %lu), sending complete database", 499c19800e8SDoug Rabson s->name, (unsigned long)s->version, (unsigned long)ver); 5005e9cd1aeSAssar Westerlund return send_complete (context, s, database, current_version); 501b528cefcSMark Murray } 502c19800e8SDoug Rabson } 503c19800e8SDoug Rabson 504c19800e8SDoug Rabson krb5_warnx(context, 505c19800e8SDoug Rabson "syncing slave %s from version %lu to version %lu", 506c19800e8SDoug Rabson s->name, (unsigned long)s->version, 507c19800e8SDoug Rabson (unsigned long)current_version); 508c19800e8SDoug Rabson 509c19800e8SDoug Rabson ret = krb5_data_alloc (&data, right - left + 4); 510c19800e8SDoug Rabson if (ret) { 511*ae771770SStanislav Sedov krb5_storage_free(sp); 512c19800e8SDoug Rabson krb5_warn (context, ret, "send_diffs: krb5_data_alloc"); 513c19800e8SDoug Rabson slave_dead(context, s); 514c19800e8SDoug Rabson return 1; 515c19800e8SDoug Rabson } 5168373020dSJacques Vidrine krb5_storage_read (sp, (char *)data.data + 4, data.length - 4); 517b528cefcSMark Murray krb5_storage_free(sp); 518b528cefcSMark Murray 519c19800e8SDoug Rabson sp = krb5_storage_from_data (&data); 520c19800e8SDoug Rabson if (sp == NULL) { 521c19800e8SDoug Rabson krb5_warnx (context, "send_diffs: krb5_storage_from_data"); 522c19800e8SDoug Rabson slave_dead(context, s); 523c19800e8SDoug Rabson return 1; 524c19800e8SDoug Rabson } 525c19800e8SDoug Rabson krb5_store_int32 (sp, FOR_YOU); 526c19800e8SDoug Rabson krb5_storage_free(sp); 527b528cefcSMark Murray 5285e9cd1aeSAssar Westerlund ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); 5298373020dSJacques Vidrine krb5_data_free(&data); 530b528cefcSMark Murray 531b528cefcSMark Murray if (ret) { 532c19800e8SDoug Rabson krb5_warn (context, ret, "send_diffs: krb5_write_priv_message"); 533c19800e8SDoug Rabson slave_dead(context, s); 534b528cefcSMark Murray return 1; 535b528cefcSMark Murray } 5368373020dSJacques Vidrine slave_seen(s); 5378373020dSJacques Vidrine 538c19800e8SDoug Rabson s->version = current_version; 539c19800e8SDoug Rabson 540b528cefcSMark Murray return 0; 541b528cefcSMark Murray } 542b528cefcSMark Murray 543b528cefcSMark Murray static int 544b528cefcSMark Murray process_msg (krb5_context context, slave *s, int log_fd, 545c19800e8SDoug Rabson const char *database, uint32_t current_version) 546b528cefcSMark Murray { 547b528cefcSMark Murray int ret = 0; 5485e9cd1aeSAssar Westerlund krb5_data out; 549b528cefcSMark Murray krb5_storage *sp; 550b528cefcSMark Murray int32_t tmp; 551b528cefcSMark Murray 5525e9cd1aeSAssar Westerlund ret = krb5_read_priv_message(context, s->ac, &s->fd, &out); 553b528cefcSMark Murray if(ret) { 5545e9cd1aeSAssar Westerlund krb5_warn (context, ret, "error reading message from %s", s->name); 555b528cefcSMark Murray return 1; 556b528cefcSMark Murray } 557b528cefcSMark Murray 558b528cefcSMark Murray sp = krb5_storage_from_mem (out.data, out.length); 559c19800e8SDoug Rabson if (sp == NULL) { 560c19800e8SDoug Rabson krb5_warnx (context, "process_msg: no memory"); 561c19800e8SDoug Rabson krb5_data_free (&out); 562c19800e8SDoug Rabson return 1; 563c19800e8SDoug Rabson } 564c19800e8SDoug Rabson if (krb5_ret_int32 (sp, &tmp) != 0) { 565c19800e8SDoug Rabson krb5_warnx (context, "process_msg: client send too short command"); 566c19800e8SDoug Rabson krb5_data_free (&out); 567c19800e8SDoug Rabson return 1; 568c19800e8SDoug Rabson } 569b528cefcSMark Murray switch (tmp) { 570b528cefcSMark Murray case I_HAVE : 571c19800e8SDoug Rabson ret = krb5_ret_int32 (sp, &tmp); 572c19800e8SDoug Rabson if (ret != 0) { 573c19800e8SDoug Rabson krb5_warnx (context, "process_msg: client send too I_HAVE data"); 574b528cefcSMark Murray break; 575c19800e8SDoug Rabson } 576c19800e8SDoug Rabson /* new started slave that have old log */ 577c19800e8SDoug Rabson if (s->version == 0 && tmp != 0) { 578*ae771770SStanislav Sedov if (current_version < (uint32_t)tmp) { 579*ae771770SStanislav Sedov krb5_warnx (context, "Slave %s (version %lu) have later version " 580*ae771770SStanislav Sedov "the master (version %lu) OUT OF SYNC", 581*ae771770SStanislav Sedov s->name, (unsigned long)tmp, 582*ae771770SStanislav Sedov (unsigned long)current_version); 583*ae771770SStanislav Sedov } 584c19800e8SDoug Rabson s->version = tmp; 585c19800e8SDoug Rabson } 586*ae771770SStanislav Sedov if ((uint32_t)tmp < s->version) { 587c19800e8SDoug Rabson krb5_warnx (context, "Slave claims to not have " 588c19800e8SDoug Rabson "version we already sent to it"); 589c19800e8SDoug Rabson } else { 590c19800e8SDoug Rabson ret = send_diffs (context, s, log_fd, database, current_version); 591c19800e8SDoug Rabson } 592c19800e8SDoug Rabson break; 593c19800e8SDoug Rabson case I_AM_HERE : 594c19800e8SDoug Rabson break; 595c19800e8SDoug Rabson case ARE_YOU_THERE: 596b528cefcSMark Murray case FOR_YOU : 597b528cefcSMark Murray default : 598b528cefcSMark Murray krb5_warnx (context, "Ignoring command %d", tmp); 599b528cefcSMark Murray break; 600b528cefcSMark Murray } 601b528cefcSMark Murray 602b528cefcSMark Murray krb5_data_free (&out); 603*ae771770SStanislav Sedov krb5_storage_free (sp); 6048373020dSJacques Vidrine 6058373020dSJacques Vidrine slave_seen(s); 6068373020dSJacques Vidrine 607b528cefcSMark Murray return ret; 608b528cefcSMark Murray } 609b528cefcSMark Murray 6108373020dSJacques Vidrine #define SLAVE_NAME "Name" 6118373020dSJacques Vidrine #define SLAVE_ADDRESS "Address" 6128373020dSJacques Vidrine #define SLAVE_VERSION "Version" 6138373020dSJacques Vidrine #define SLAVE_STATUS "Status" 6148373020dSJacques Vidrine #define SLAVE_SEEN "Last Seen" 6158373020dSJacques Vidrine 616c19800e8SDoug Rabson static FILE * 617c19800e8SDoug Rabson open_stats(krb5_context context) 618c19800e8SDoug Rabson { 619c19800e8SDoug Rabson char *statfile = NULL; 620c19800e8SDoug Rabson const char *fn; 621c19800e8SDoug Rabson FILE *f; 622c19800e8SDoug Rabson 623c19800e8SDoug Rabson if (slave_stats_file) 624c19800e8SDoug Rabson fn = slave_stats_file; 625c19800e8SDoug Rabson else { 626c19800e8SDoug Rabson asprintf(&statfile, "%s/slaves-stats", hdb_db_dir(context)); 627c19800e8SDoug Rabson fn = krb5_config_get_string_default(context, 628c19800e8SDoug Rabson NULL, 629c19800e8SDoug Rabson statfile, 630c19800e8SDoug Rabson "kdc", 631c19800e8SDoug Rabson "iprop-stats", 632c19800e8SDoug Rabson NULL); 633c19800e8SDoug Rabson } 634c19800e8SDoug Rabson f = fopen(fn, "w"); 635c19800e8SDoug Rabson if (statfile) 636c19800e8SDoug Rabson free(statfile); 637c19800e8SDoug Rabson 638c19800e8SDoug Rabson return f; 639c19800e8SDoug Rabson } 640c19800e8SDoug Rabson 6418373020dSJacques Vidrine static void 642c19800e8SDoug Rabson write_master_down(krb5_context context) 643c19800e8SDoug Rabson { 644c19800e8SDoug Rabson char str[100]; 645c19800e8SDoug Rabson time_t t = time(NULL); 646c19800e8SDoug Rabson FILE *fp; 647c19800e8SDoug Rabson 648c19800e8SDoug Rabson fp = open_stats(context); 649c19800e8SDoug Rabson if (fp == NULL) 650c19800e8SDoug Rabson return; 651c19800e8SDoug Rabson krb5_format_time(context, t, str, sizeof(str), TRUE); 652c19800e8SDoug Rabson fprintf(fp, "master down at %s\n", str); 653c19800e8SDoug Rabson 654c19800e8SDoug Rabson fclose(fp); 655c19800e8SDoug Rabson } 656c19800e8SDoug Rabson 657c19800e8SDoug Rabson static void 658c19800e8SDoug Rabson write_stats(krb5_context context, slave *slaves, uint32_t current_version) 6598373020dSJacques Vidrine { 660bbd80c28SJacques Vidrine char str[100]; 6618373020dSJacques Vidrine rtbl_t tbl; 6628373020dSJacques Vidrine time_t t = time(NULL); 6638373020dSJacques Vidrine FILE *fp; 6648373020dSJacques Vidrine 665c19800e8SDoug Rabson fp = open_stats(context); 6668373020dSJacques Vidrine if (fp == NULL) 6678373020dSJacques Vidrine return; 6688373020dSJacques Vidrine 669c19800e8SDoug Rabson krb5_format_time(context, t, str, sizeof(str), TRUE); 6708373020dSJacques Vidrine fprintf(fp, "Status for slaves, last updated: %s\n\n", str); 6718373020dSJacques Vidrine 6728373020dSJacques Vidrine fprintf(fp, "Master version: %lu\n\n", (unsigned long)current_version); 6738373020dSJacques Vidrine 6748373020dSJacques Vidrine tbl = rtbl_create(); 6758373020dSJacques Vidrine if (tbl == NULL) { 6768373020dSJacques Vidrine fclose(fp); 6778373020dSJacques Vidrine return; 6788373020dSJacques Vidrine } 6798373020dSJacques Vidrine 6808373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_NAME, 0); 6818373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_ADDRESS, 0); 6828373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_VERSION, RTBL_ALIGN_RIGHT); 6838373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_STATUS, 0); 6848373020dSJacques Vidrine rtbl_add_column(tbl, SLAVE_SEEN, 0); 6858373020dSJacques Vidrine 6868373020dSJacques Vidrine rtbl_set_prefix(tbl, " "); 6878373020dSJacques Vidrine rtbl_set_column_prefix(tbl, SLAVE_NAME, ""); 6888373020dSJacques Vidrine 6898373020dSJacques Vidrine while (slaves) { 6908373020dSJacques Vidrine krb5_address addr; 6918373020dSJacques Vidrine krb5_error_code ret; 6928373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_NAME, slaves->name); 6938373020dSJacques Vidrine ret = krb5_sockaddr2address (context, 6948373020dSJacques Vidrine (struct sockaddr*)&slaves->addr, &addr); 6958373020dSJacques Vidrine if(ret == 0) { 6968373020dSJacques Vidrine krb5_print_address(&addr, str, sizeof(str), NULL); 6978373020dSJacques Vidrine krb5_free_address(context, &addr); 6988373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_ADDRESS, str); 6998373020dSJacques Vidrine } else 7008373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_ADDRESS, "<unknown>"); 7018373020dSJacques Vidrine 7028373020dSJacques Vidrine snprintf(str, sizeof(str), "%u", (unsigned)slaves->version); 7038373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_VERSION, str); 7048373020dSJacques Vidrine 7058373020dSJacques Vidrine if (slaves->flags & SLAVE_F_DEAD) 7068373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_STATUS, "Down"); 7078373020dSJacques Vidrine else 7088373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_STATUS, "Up"); 7098373020dSJacques Vidrine 710c19800e8SDoug Rabson ret = krb5_format_time(context, slaves->seen, str, sizeof(str), TRUE); 7118373020dSJacques Vidrine rtbl_add_column_entry(tbl, SLAVE_SEEN, str); 7128373020dSJacques Vidrine 7138373020dSJacques Vidrine slaves = slaves->next; 7148373020dSJacques Vidrine } 7158373020dSJacques Vidrine 7168373020dSJacques Vidrine rtbl_format(tbl, fp); 7178373020dSJacques Vidrine rtbl_destroy(tbl); 7188373020dSJacques Vidrine 7198373020dSJacques Vidrine fclose(fp); 7208373020dSJacques Vidrine } 7218373020dSJacques Vidrine 7228373020dSJacques Vidrine 723*ae771770SStanislav Sedov static char sHDB[] = "HDB:"; 7245e9cd1aeSAssar Westerlund static char *realm; 7255e9cd1aeSAssar Westerlund static int version_flag; 7265e9cd1aeSAssar Westerlund static int help_flag; 727*ae771770SStanislav Sedov static char *keytab_str = sHDB; 7285e9cd1aeSAssar Westerlund static char *database; 729c19800e8SDoug Rabson static char *config_file; 730c19800e8SDoug Rabson static char *port_str; 731*ae771770SStanislav Sedov #ifdef SUPPORT_DETACH 732c19800e8SDoug Rabson static int detach_from_console = 0; 733*ae771770SStanislav Sedov #endif 7345e9cd1aeSAssar Westerlund 7355e9cd1aeSAssar Westerlund static struct getargs args[] = { 736*ae771770SStanislav Sedov { "config-file", 'c', arg_string, &config_file, NULL, NULL }, 737*ae771770SStanislav Sedov { "realm", 'r', arg_string, &realm, NULL, NULL }, 7385e9cd1aeSAssar Westerlund { "keytab", 'k', arg_string, &keytab_str, 7395e9cd1aeSAssar Westerlund "keytab to get authentication from", "kspec" }, 7405e9cd1aeSAssar Westerlund { "database", 'd', arg_string, &database, "database", "file"}, 741*ae771770SStanislav Sedov { "slave-stats-file", 0, arg_string, rk_UNCONST(&slave_stats_file), 742c19800e8SDoug Rabson "file for slave status information", "file"}, 743*ae771770SStanislav Sedov { "time-missing", 0, arg_string, rk_UNCONST(&slave_time_missing), 744c19800e8SDoug Rabson "time before slave is polled for presence", "time"}, 745*ae771770SStanislav Sedov { "time-gone", 0, arg_string, rk_UNCONST(&slave_time_gone), 746c19800e8SDoug Rabson "time of inactivity after which a slave is considered gone", "time"}, 747c19800e8SDoug Rabson { "port", 0, arg_string, &port_str, 748c19800e8SDoug Rabson "port ipropd will listen to", "port"}, 749*ae771770SStanislav Sedov #ifdef SUPPORT_DETACH 750c19800e8SDoug Rabson { "detach", 0, arg_flag, &detach_from_console, 751*ae771770SStanislav Sedov "detach from console", NULL }, 752*ae771770SStanislav Sedov #endif 753*ae771770SStanislav Sedov { "hostname", 0, arg_string, rk_UNCONST(&master_hostname), 754c19800e8SDoug Rabson "hostname of master (if not same as hostname)", "hostname" }, 755*ae771770SStanislav Sedov { "version", 0, arg_flag, &version_flag, NULL, NULL }, 756*ae771770SStanislav Sedov { "help", 0, arg_flag, &help_flag, NULL, NULL } 757b528cefcSMark Murray }; 7585e9cd1aeSAssar Westerlund static int num_args = sizeof(args) / sizeof(args[0]); 759b528cefcSMark Murray 760b528cefcSMark Murray int 761b528cefcSMark Murray main(int argc, char **argv) 762b528cefcSMark Murray { 763b528cefcSMark Murray krb5_error_code ret; 764b528cefcSMark Murray krb5_context context; 765b528cefcSMark Murray void *kadm_handle; 766b528cefcSMark Murray kadm5_server_context *server_context; 767b528cefcSMark Murray kadm5_config_params conf; 768*ae771770SStanislav Sedov krb5_socket_t signal_fd, listen_fd; 769b528cefcSMark Murray int log_fd; 770b528cefcSMark Murray slave *slaves = NULL; 771c19800e8SDoug Rabson uint32_t current_version = 0, old_version = 0; 7725e9cd1aeSAssar Westerlund krb5_keytab keytab; 773c19800e8SDoug Rabson int optidx; 774c19800e8SDoug Rabson char **files; 775b528cefcSMark Murray 776c19800e8SDoug Rabson optidx = krb5_program_setup(&context, argc, argv, args, num_args, NULL); 777b528cefcSMark Murray 778b528cefcSMark Murray if(help_flag) 779b528cefcSMark Murray krb5_std_usage(0, args, num_args); 780b528cefcSMark Murray if(version_flag) { 781b528cefcSMark Murray print_version(NULL); 782b528cefcSMark Murray exit(0); 783b528cefcSMark Murray } 784b528cefcSMark Murray 785c19800e8SDoug Rabson setup_signal(); 786c19800e8SDoug Rabson 787c19800e8SDoug Rabson if (config_file == NULL) { 788c19800e8SDoug Rabson asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); 789c19800e8SDoug Rabson if (config_file == NULL) 790c19800e8SDoug Rabson errx(1, "out of memory"); 791c19800e8SDoug Rabson } 792c19800e8SDoug Rabson 793c19800e8SDoug Rabson ret = krb5_prepend_config_files_default(config_file, &files); 794c19800e8SDoug Rabson if (ret) 795c19800e8SDoug Rabson krb5_err(context, 1, ret, "getting configuration files"); 796c19800e8SDoug Rabson 797c19800e8SDoug Rabson ret = krb5_set_config_files(context, files); 798c19800e8SDoug Rabson krb5_free_config_files(files); 799c19800e8SDoug Rabson if (ret) 800c19800e8SDoug Rabson krb5_err(context, 1, ret, "reading configuration files"); 801c19800e8SDoug Rabson 802c19800e8SDoug Rabson time_before_gone = parse_time (slave_time_gone, "s"); 803c19800e8SDoug Rabson if (time_before_gone < 0) 804c19800e8SDoug Rabson krb5_errx (context, 1, "couldn't parse time: %s", slave_time_gone); 805c19800e8SDoug Rabson time_before_missing = parse_time (slave_time_missing, "s"); 806c19800e8SDoug Rabson if (time_before_missing < 0) 807c19800e8SDoug Rabson krb5_errx (context, 1, "couldn't parse time: %s", slave_time_missing); 808c19800e8SDoug Rabson 809*ae771770SStanislav Sedov #ifdef SUPPORT_DETACH 810c19800e8SDoug Rabson if (detach_from_console) 811c19800e8SDoug Rabson daemon(0, 0); 812*ae771770SStanislav Sedov #endif 8134137ff4cSJacques Vidrine pidfile (NULL); 8145e9cd1aeSAssar Westerlund krb5_openlog (context, "ipropd-master", &log_facility); 8155e9cd1aeSAssar Westerlund krb5_set_warn_dest(context, log_facility); 8165e9cd1aeSAssar Westerlund 8175e9cd1aeSAssar Westerlund ret = krb5_kt_register(context, &hdb_kt_ops); 8185e9cd1aeSAssar Westerlund if(ret) 8195e9cd1aeSAssar Westerlund krb5_err(context, 1, ret, "krb5_kt_register"); 8205e9cd1aeSAssar Westerlund 8215e9cd1aeSAssar Westerlund ret = krb5_kt_resolve(context, keytab_str, &keytab); 8225e9cd1aeSAssar Westerlund if(ret) 8235e9cd1aeSAssar Westerlund krb5_err(context, 1, ret, "krb5_kt_resolve: %s", keytab_str); 8245e9cd1aeSAssar Westerlund 825b528cefcSMark Murray memset(&conf, 0, sizeof(conf)); 826b528cefcSMark Murray if(realm) { 827b528cefcSMark Murray conf.mask |= KADM5_CONFIG_REALM; 828b528cefcSMark Murray conf.realm = realm; 829b528cefcSMark Murray } 8305e9cd1aeSAssar Westerlund ret = kadm5_init_with_skey_ctx (context, 831b528cefcSMark Murray KADM5_ADMIN_SERVICE, 832b528cefcSMark Murray NULL, 833b528cefcSMark Murray KADM5_ADMIN_SERVICE, 834b528cefcSMark Murray &conf, 0, 0, 835b528cefcSMark Murray &kadm_handle); 836b528cefcSMark Murray if (ret) 837b528cefcSMark Murray krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); 838b528cefcSMark Murray 839b528cefcSMark Murray server_context = (kadm5_server_context *)kadm_handle; 840b528cefcSMark Murray 841b528cefcSMark Murray log_fd = open (server_context->log_context.log_file, O_RDONLY, 0); 842b528cefcSMark Murray if (log_fd < 0) 843b528cefcSMark Murray krb5_err (context, 1, errno, "open %s", 844b528cefcSMark Murray server_context->log_context.log_file); 845b528cefcSMark Murray 846b528cefcSMark Murray signal_fd = make_signal_socket (context); 847c19800e8SDoug Rabson listen_fd = make_listen_socket (context, port_str); 848b528cefcSMark Murray 849c19800e8SDoug Rabson kadm5_log_get_version_fd (log_fd, ¤t_version); 8505e9cd1aeSAssar Westerlund 851c19800e8SDoug Rabson krb5_warnx(context, "ipropd-master started at version: %lu", 852c19800e8SDoug Rabson (unsigned long)current_version); 853c19800e8SDoug Rabson 854c19800e8SDoug Rabson while(exit_flag == 0){ 855b528cefcSMark Murray slave *p; 856b528cefcSMark Murray fd_set readset; 857b528cefcSMark Murray int max_fd = 0; 858b528cefcSMark Murray struct timeval to = {30, 0}; 859c19800e8SDoug Rabson uint32_t vers; 860b528cefcSMark Murray 861*ae771770SStanislav Sedov #ifndef NO_LIMIT_FD_SETSIZE 8625e9cd1aeSAssar Westerlund if (signal_fd >= FD_SETSIZE || listen_fd >= FD_SETSIZE) 8635e9cd1aeSAssar Westerlund krb5_errx (context, 1, "fd too large"); 864*ae771770SStanislav Sedov #endif 8655e9cd1aeSAssar Westerlund 866b528cefcSMark Murray FD_ZERO(&readset); 867b528cefcSMark Murray FD_SET(signal_fd, &readset); 868b528cefcSMark Murray max_fd = max(max_fd, signal_fd); 869b528cefcSMark Murray FD_SET(listen_fd, &readset); 870b528cefcSMark Murray max_fd = max(max_fd, listen_fd); 871b528cefcSMark Murray 872b528cefcSMark Murray for (p = slaves; p != NULL; p = p->next) { 873bbd80c28SJacques Vidrine if (p->flags & SLAVE_F_DEAD) 874bbd80c28SJacques Vidrine continue; 875b528cefcSMark Murray FD_SET(p->fd, &readset); 876b528cefcSMark Murray max_fd = max(max_fd, p->fd); 877b528cefcSMark Murray } 878b528cefcSMark Murray 879b528cefcSMark Murray ret = select (max_fd + 1, 880b528cefcSMark Murray &readset, NULL, NULL, &to); 881b528cefcSMark Murray if (ret < 0) { 882b528cefcSMark Murray if (errno == EINTR) 883b528cefcSMark Murray continue; 884b528cefcSMark Murray else 885b528cefcSMark Murray krb5_err (context, 1, errno, "select"); 886b528cefcSMark Murray } 887b528cefcSMark Murray 888b528cefcSMark Murray if (ret == 0) { 889b528cefcSMark Murray old_version = current_version; 8905e9cd1aeSAssar Westerlund kadm5_log_get_version_fd (log_fd, ¤t_version); 891b528cefcSMark Murray 892c19800e8SDoug Rabson if (current_version > old_version) { 893c19800e8SDoug Rabson krb5_warnx(context, 894c19800e8SDoug Rabson "Missed a signal, updating slaves %lu to %lu", 895c19800e8SDoug Rabson (unsigned long)old_version, 896c19800e8SDoug Rabson (unsigned long)current_version); 897bbd80c28SJacques Vidrine for (p = slaves; p != NULL; p = p->next) { 898bbd80c28SJacques Vidrine if (p->flags & SLAVE_F_DEAD) 899bbd80c28SJacques Vidrine continue; 9005e9cd1aeSAssar Westerlund send_diffs (context, p, log_fd, database, current_version); 901b528cefcSMark Murray } 902bbd80c28SJacques Vidrine } 903c19800e8SDoug Rabson } 904b528cefcSMark Murray 905b528cefcSMark Murray if (ret && FD_ISSET(signal_fd, &readset)) { 906*ae771770SStanislav Sedov #ifndef NO_UNIX_SOCKETS 907b528cefcSMark Murray struct sockaddr_un peer_addr; 908*ae771770SStanislav Sedov #else 909*ae771770SStanislav Sedov struct sockaddr_storage peer_addr; 910*ae771770SStanislav Sedov #endif 9115e9cd1aeSAssar Westerlund socklen_t peer_len = sizeof(peer_addr); 912b528cefcSMark Murray 9134137ff4cSJacques Vidrine if(recvfrom(signal_fd, (void *)&vers, sizeof(vers), 0, 914b528cefcSMark Murray (struct sockaddr *)&peer_addr, &peer_len) < 0) { 915b528cefcSMark Murray krb5_warn (context, errno, "recvfrom"); 916b528cefcSMark Murray continue; 917b528cefcSMark Murray } 918b528cefcSMark Murray --ret; 919c19800e8SDoug Rabson assert(ret >= 0); 920b528cefcSMark Murray old_version = current_version; 9215e9cd1aeSAssar Westerlund kadm5_log_get_version_fd (log_fd, ¤t_version); 922c19800e8SDoug Rabson if (current_version > old_version) { 923c19800e8SDoug Rabson krb5_warnx(context, 924c19800e8SDoug Rabson "Got a signal, updating slaves %lu to %lu", 925c19800e8SDoug Rabson (unsigned long)old_version, 926c19800e8SDoug Rabson (unsigned long)current_version); 927*ae771770SStanislav Sedov for (p = slaves; p != NULL; p = p->next) { 928*ae771770SStanislav Sedov if (p->flags & SLAVE_F_DEAD) 929*ae771770SStanislav Sedov continue; 9305e9cd1aeSAssar Westerlund send_diffs (context, p, log_fd, database, current_version); 931*ae771770SStanislav Sedov } 932c19800e8SDoug Rabson } else { 933c19800e8SDoug Rabson krb5_warnx(context, 934c19800e8SDoug Rabson "Got a signal, but no update in log version %lu", 935c19800e8SDoug Rabson (unsigned long)current_version); 936c19800e8SDoug Rabson } 937b528cefcSMark Murray } 938b528cefcSMark Murray 939c19800e8SDoug Rabson for(p = slaves; p != NULL; p = p->next) { 940bbd80c28SJacques Vidrine if (p->flags & SLAVE_F_DEAD) 941bbd80c28SJacques Vidrine continue; 942c19800e8SDoug Rabson if (ret && FD_ISSET(p->fd, &readset)) { 943adb0ddaeSAssar Westerlund --ret; 944c19800e8SDoug Rabson assert(ret >= 0); 9455e9cd1aeSAssar Westerlund if(process_msg (context, p, log_fd, database, current_version)) 946c19800e8SDoug Rabson slave_dead(context, p); 947c19800e8SDoug Rabson } else if (slave_gone_p (p)) 948c19800e8SDoug Rabson slave_dead(context, p); 949*ae771770SStanislav Sedov else if (slave_missing_p (p)) 950c19800e8SDoug Rabson send_are_you_there (context, p); 951b528cefcSMark Murray } 952b528cefcSMark Murray 953b528cefcSMark Murray if (ret && FD_ISSET(listen_fd, &readset)) { 9545e9cd1aeSAssar Westerlund add_slave (context, keytab, &slaves, listen_fd); 955b528cefcSMark Murray --ret; 956c19800e8SDoug Rabson assert(ret >= 0); 957b528cefcSMark Murray } 9588373020dSJacques Vidrine write_stats(context, slaves, current_version); 959b528cefcSMark Murray } 960b528cefcSMark Murray 961*ae771770SStanislav Sedov if(exit_flag == SIGINT || exit_flag == SIGTERM) 962c19800e8SDoug Rabson krb5_warnx(context, "%s terminated", getprogname()); 963*ae771770SStanislav Sedov #ifdef SIGXCPU 964*ae771770SStanislav Sedov else if(exit_flag == SIGXCPU) 965*ae771770SStanislav Sedov krb5_warnx(context, "%s CPU time limit exceeded", getprogname()); 966*ae771770SStanislav Sedov #endif 967c19800e8SDoug Rabson else 968*ae771770SStanislav Sedov krb5_warnx(context, "%s unexpected exit reason: %ld", 969*ae771770SStanislav Sedov getprogname(), (long)exit_flag); 970c19800e8SDoug Rabson 971c19800e8SDoug Rabson write_master_down(context); 972c19800e8SDoug Rabson 973b528cefcSMark Murray return 0; 974b528cefcSMark Murray } 975