* or implied warranty.
*/
-/*
- * XXX We need to modify the protocol so that an acknowledge is set
- * after each block, instead after the entire series is sent over.
- * The reason for this is so that error packets can get interpreted
- * right away. If you don't do this, the sender may never get the
- * error packet, because it will die an EPIPE trying to complete the
- * write...
- */
+#include "k5-int.h"
+#include "com_err.h"
+#include "fake-addrinfo.h"
-#include <stdio.h>
+#include <locale.h>
#include <ctype.h>
#include <sys/file.h>
#include <signal.h>
-#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netdb.h>
#include <syslog.h>
-#include "k5-int.h"
-#include "com_err.h"
-#include "fake-addrinfo.h"
-#include <errno.h>
-
#include "kprop.h"
#include <iprop_hdr.h>
#include "iprop.h"
#endif
#define SYSLOG_CLASS LOG_DAEMON
-#define INITIAL_TIMER 10
-char *def_realm = NULL;
int runonce = 0;
/*
- * Global fd to close upon alarm time-out.
- */
-volatile int gfd = -1;
-
-/*
* This struct simulates the use of _kadm5_server_handle_t
*
* This is a COPY of kadm5_server_handle_t from
* lib/kadm5/clnt/client_internal.h!
*/
typedef struct _kadm5_iprop_handle_t {
- krb5_ui_4 magic_number;
- krb5_ui_4 struct_version;
- krb5_ui_4 api_version;
- char *cache_name;
- int destroy_cache;
- CLIENT *clnt;
- krb5_context context;
+ krb5_ui_4 magic_number;
+ krb5_ui_4 struct_version;
+ krb5_ui_4 api_version;
+ char *cache_name;
+ int destroy_cache;
+ CLIENT *clnt;
+ krb5_context context;
kadm5_config_params params;
struct _kadm5_iprop_handle_t *lhandle;
} *kadm5_iprop_handle_t;
-
static char *kprop_version = KPROP_PROT_VERSION;
-char *progname;
-int debug = 0;
-char *srvtab = 0;
-int standalone = 0;
-
-krb5_principal server; /* This is our server principal name */
-krb5_principal client; /* This is who we're talking to */
-krb5_context kpropd_context;
-krb5_auth_context auth_context;
-char *realm = NULL; /* Our realm */
-char *file = KPROPD_DEFAULT_FILE;
-char *temp_file_name;
-char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
-char *kerb_database = NULL;
-char *acl_file_name = KPROPD_ACL_FILE;
-
-krb5_address *sender_addr;
-krb5_address *receiver_addr;
-const char *port = KPROP_SERVICE;
-
-char **db_args = NULL;
-int db_args_size = 0;
-
-void PRS(char**);
-int do_standalone(iprop_role iproprole);
-void doit(int);
-krb5_error_code do_iprop(kdb_log_context *log_ctx);
-void kerberos_authenticate(krb5_context, int, krb5_principal *,
- krb5_enctype *, struct sockaddr_storage *);
-krb5_boolean authorized_principal(krb5_context, krb5_principal, krb5_enctype);
-void recv_database(krb5_context, int, int, krb5_data *);
-void load_database(krb5_context, char *, char *);
-void send_error(krb5_context, int, krb5_error_code, char *);
-void recv_error(krb5_context, krb5_data *);
-unsigned int backoff_from_master(int *);
-
-static kadm5_ret_t
-kadm5_get_kiprop_host_srv_name(krb5_context context,
- const char *realm_name,
- char **host_service_name);
+static kadm5_config_params params;
+
+static char *progname;
+static int debug = 0;
+static int nodaemon = 0;
+static char *srvtab = NULL;
+static int standalone = 0;
+
+static pid_t fullprop_child = (pid_t)-1;
+
+static krb5_principal server; /* This is our server principal name */
+static krb5_principal client; /* This is who we're talking to */
+static krb5_context kpropd_context;
+static krb5_auth_context auth_context;
+static char *realm = NULL; /* Our realm */
+static char *def_realm = NULL; /* Ref pointer for default realm */
+static char *file = KPROPD_DEFAULT_FILE;
+static char *temp_file_name;
+static char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
+static char *kerb_database = NULL;
+static char *acl_file_name = KPROPD_ACL_FILE;
+
+static krb5_address *sender_addr;
+static krb5_address *receiver_addr;
+static const char *port = KPROP_SERVICE;
+
+static char **db_args = NULL;
+static int db_args_size = 0;
+
+static void parse_args(char **argv);
+static void do_standalone(void);
+static void doit(int fd);
+static krb5_error_code do_iprop(void);
+static void kerberos_authenticate(krb5_context context, int fd,
+ krb5_principal *clientp, krb5_enctype *etype,
+ struct sockaddr_storage *my_sin);
+static krb5_boolean authorized_principal(krb5_context context,
+ krb5_principal p,
+ krb5_enctype auth_etype);
+static void recv_database(krb5_context context, int fd, int database_fd,
+ krb5_data *confmsg);
+static void load_database(krb5_context context, char *kdb_util,
+ char *database_file_name);
+static void send_error(krb5_context context, int fd, krb5_error_code err_code,
+ char *err_text);
+static void recv_error(krb5_context context, krb5_data *inbuf);
+static unsigned int backoff_from_master(int *cnt);
+static kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context,
+ const char *realm_name,
+ char **host_service_name);
-static void usage()
+static void
+usage()
{
fprintf(stderr,
_("\nUsage: %s [-r realm] [-s srvtab] [-dS] [-f slave_file]\n"),
progname);
fprintf(stderr, _("\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n"));
fprintf(stderr, _("\t[-x db_args]* [-P port] [-a acl_file]\n"));
+ fprintf(stderr, _("\t[-A admin_server]\n"));
+ exit(1);
+}
+
+typedef void (*sig_handler_fn)(int sig);
+
+static void
+signal_wrapper(int sig, sig_handler_fn handler)
+{
+#ifdef POSIX_SIGNALS
+ struct sigaction s_action;
+
+ memset(&s_action, 0, sizeof(s_action));
+ sigemptyset(&s_action.sa_mask);
+ s_action.sa_handler = handler;
+ sigaction(sig, &s_action, NULL);
+#else
+ signal(sig, handler);
+#endif
+}
+
+static void
+alarm_handler(int sig)
+{
+ static char *timeout_msg = "Full propagation timed out\n";
+
+ write(STDERR_FILENO, timeout_msg, strlen(timeout_msg));
exit(1);
}
+static void
+usr1_handler(int sig)
+{
+ /* Nothing to do, just let the signal interrupt sleep(). */
+}
+
+static void
+kill_do_standalone(int sig)
+{
+ if (fullprop_child > 0) {
+ if (debug) {
+ fprintf(stderr, _("Killing fullprop child (%d)\n"),
+ (int)fullprop_child);
+ }
+ kill(fullprop_child, sig);
+ }
+ /* Make sure our exit status code reflects our having been signaled */
+ signal_wrapper(sig, SIG_DFL);
+ kill(getpid(), sig);
+}
+
+static void
+atexit_kill_do_standalone(void)
+{
+ if (fullprop_child > 0)
+ kill(fullprop_child, SIGHUP);
+}
+
int
-main(argc, argv)
- int argc;
- char **argv;
+main(int argc, char **argv)
{
krb5_error_code retval;
- int ret = 0;
kdb_log_context *log_ctx;
+ int devnull, sock;
+ struct stat st;
- setlocale(LC_MESSAGES, "");
- PRS(argv);
+ setlocale(LC_ALL, "");
+ parse_args(argv);
+
+ if (fstat(0, &st) == -1) {
+ com_err(progname, errno, _("while checking if stdin is a socket"));
+ exit(1);
+ }
+ /*
+ * Detect whether we're running from inetd; if not then we're in
+ * standalone mode.
+ */
+ standalone = !S_ISSOCK(st.st_mode);
log_ctx = kpropd_context->kdblog_context;
- {
-#ifdef POSIX_SIGNALS
- struct sigaction s_action;
- memset(&s_action, 0, sizeof(s_action));
- sigemptyset(&s_action.sa_mask);
- s_action.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &s_action, NULL);
-#else
- signal(SIGPIPE, SIG_IGN);
-#endif
- }
+ signal_wrapper(SIGPIPE, SIG_IGN);
- if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
+ if (standalone) {
+ /* "ready" is a sentinel for the test framework. */
+ if (!debug && !nodaemon) {
+ daemon(0, 0);
+ } else {
+ printf(_("ready\n"));
+ fflush(stdout);
+ }
+ } else {
/*
- * We wanna do iprop !
+ * We're an inetd nowait service. Let's not risk anything
+ * read/write from/to the inetd socket unintentionally.
*/
- retval = do_iprop(log_ctx);
- if (retval) {
- com_err(progname, retval,
- _("do_iprop failed.\n"));
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull == -1) {
+ syslog(LOG_ERR, _("Could not open /dev/null: %s"),
+ strerror(errno));
exit(1);
}
- } else {
- if (standalone)
- ret = do_standalone(IPROP_NULL);
- else
- doit(0);
+ sock = dup(0);
+ if (sock == -1) {
+ syslog(LOG_ERR, _("Could not dup the inetd socket: %s"),
+ strerror(errno));
+ exit(1);
+ }
+
+ dup2(devnull, STDIN_FILENO);
+ dup2(devnull, STDOUT_FILENO);
+ dup2(devnull, STDERR_FILENO);
+ close(devnull);
+ doit(sock);
+ exit(0);
}
- exit(ret);
-}
+ if (log_ctx == NULL || log_ctx->iproprole != IPROP_SLAVE) {
+ do_standalone();
+ /* do_standalone() should never return */
+ assert(0);
+ }
-static void resync_alarm(int sn)
-{
- close (gfd);
- if (debug)
- fprintf(stderr, _("resync_alarm: closing fd: %d\n"), gfd);
- gfd = -1;
+ /*
+ * This is the iprop case. We'll fork a child to run do_standalone(). The
+ * parent will run do_iprop(). We try to kill the child if we get killed.
+ * Catch SIGUSR1, which can be used to interrupt the sleep timer and force
+ * an iprop request.
+ */
+ signal_wrapper(SIGHUP, kill_do_standalone);
+ signal_wrapper(SIGINT, kill_do_standalone);
+ signal_wrapper(SIGQUIT, kill_do_standalone);
+ signal_wrapper(SIGTERM, kill_do_standalone);
+ signal_wrapper(SIGSEGV, kill_do_standalone);
+ signal_wrapper(SIGUSR1, usr1_handler);
+ atexit(atexit_kill_do_standalone);
+ fullprop_child = fork();
+ switch (fullprop_child) {
+ case -1:
+ com_err(progname, errno, _("do_iprop failed.\n"));
+ break;
+ case 0:
+ do_standalone();
+ /* do_standalone() should never return */
+ /* NOTREACHED */
+ break;
+ default:
+ retval = do_iprop();
+ /* do_iprop() can return due to failures and runonce. */
+ kill(fullprop_child, SIGHUP);
+ wait(NULL);
+ if (retval)
+ com_err(progname, retval, _("do_iprop failed.\n"));
+ else
+ exit(0);
+ }
+
+ exit(1);
}
/* Use getaddrinfo to determine a wildcard listener address, preferring
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
-#ifdef KRB5_USE_INET6
hints.ai_family = AF_INET6;
error = getaddrinfo(NULL, port, &hints, res);
if (error == 0)
return 0;
-#endif
hints.ai_family = AF_INET;
return getaddrinfo(NULL, port, &hints, res);
}
-int do_standalone(iprop_role iproprole)
+static void
+do_standalone()
{
- struct sockaddr_in frominet;
+ struct sockaddr_in frominet;
struct addrinfo *res;
- int finet, s;
GETPEERNAME_ARG3_TYPE fromlen;
- int ret, error, val;
- /*
- * Timer for accept/read calls, in case of network type errors.
- */
- int backoff_timer = INITIAL_TIMER;
-
-retry:
+ int finet, s, ret, error, val, status;
+ pid_t child_pid;
+ pid_t wait_pid;
error = get_wildcard_addr(&res);
if (error != 0) {
- (void) fprintf(stderr, _("getaddrinfo: %s\n"), gai_strerror(error));
+ fprintf(stderr, _("getaddrinfo: %s\n"), gai_strerror(error));
exit(1);
}
if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
com_err(progname, errno, _("while setting SO_REUSEADDR option"));
-#if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
+#if defined(IPV6_V6ONLY)
/* Make sure dual-stack support is enabled on IPv6 listener sockets if
* possible. */
val = 0;
com_err(progname, errno, _("while unsetting IPV6_V6ONLY option"));
#endif
- /*
- * We need to close the socket immediately if iprop is enabled,
- * since back-to-back full resyncs are possible, so we do not
- * linger around for too long
- */
- if (iproprole == IPROP_SLAVE) {
- struct linger linger;
-
- linger.l_onoff = 1;
- linger.l_linger = 2;
- if (setsockopt(finet, SOL_SOCKET, SO_LINGER,
- (void *)&linger, sizeof(linger)) < 0)
- com_err(progname, errno,
- _("while setting socket option (SO_LINGER)"));
- /*
- * We also want to set a timer so that the slave is not waiting
- * until infinity for an update from the master.
- */
- gfd = finet;
- signal(SIGALRM, resync_alarm);
- if (debug) {
- fprintf(stderr, "do_standalone: setting resync alarm to %d\n",
- backoff_timer);
- }
- if (alarm(backoff_timer) != 0) {
- if (debug) {
- fprintf(stderr,
- _("%s: alarm already set\n"), progname);
- }
- }
- backoff_timer *= 2;
- }
- if ((ret = bind(finet, res->ai_addr, res->ai_addrlen)) < 0) {
+ ret = bind(finet, res->ai_addr, res->ai_addrlen);
+ if (ret < 0) {
com_err(progname, errno, _("while binding listener socket"));
exit(1);
}
- if (!debug && iproprole != IPROP_SLAVE)
- daemon(1, 0);
-#ifdef PID_FILE
- if ((pidfile = fopen(PID_FILE, "w")) != NULL) {
- fprintf(pidfile, "%d\n", getpid());
- fclose(pidfile);
- } else
- com_err(progname, errno,
- _("while opening pid file %s for writing"), PID_FILE);
-#endif
if (listen(finet, 5) < 0) {
com_err(progname, errno, "in listen call");
exit(1);
}
- while (1) {
- int child_pid;
- int status;
-
+ for (;;) {
memset(&frominet, 0, sizeof(frominet));
fromlen = sizeof(frominet);
if (debug)
if (s < 0) {
int e = errno;
if (e != EINTR) {
- com_err(progname, e,
- _("while accepting connection"));
- if (e != EBADF)
- backoff_timer = INITIAL_TIMER;
+ com_err(progname, e, _("while accepting connection"));
}
- /*
- * If we got EBADF, an alarm signal handler closed
- * the file descriptor on us.
- */
- if (e != EBADF)
- close(finet);
- /*
- * An alarm could have been set and the fd closed, we
- * should retry in case of transient network error for
- * up to a couple of minutes.
- */
- if (backoff_timer > 120)
- return EINTR;
- goto retry;
}
- alarm(0);
- gfd = -1;
- if (debug && iproprole != IPROP_SLAVE)
- child_pid = 0;
- else
- child_pid = fork();
+ child_pid = fork();
switch (child_pid) {
case -1:
com_err(progname, errno, _("while forking"));
exit(1);
case 0:
- (void) close(finet);
+ close(finet);
doit(s);
close(s);
_exit(0);
default:
- /*
- * Errors should not be considered fatal in the
- * iprop case as we could have transient type
- * errors, such as network outage, etc. Sleeping
- * 3s for 2s linger interval.
- */
- if (wait(&status) < 0) {
+ do {
+ wait_pid = waitpid(child_pid, &status, 0);
+ } while (wait_pid == -1 && errno == EINTR);
+ if (wait_pid == -1) {
+ /* Something bad happened; panic. */
+ if (debug) {
+ fprintf(stderr, _("waitpid() failed to wait for doit() "
+ "(%d %s)\n"), errno, strerror(errno));
+ }
com_err(progname, errno,
_("while waiting to receive database"));
- if (iproprole != IPROP_SLAVE)
- exit(1);
- sleep(3);
+ exit(1);
+ }
+ if (debug) {
+ fprintf(stderr, _("Database load process for full propagation "
+ "completed.\n"));
}
close(s);
- if (iproprole == IPROP_SLAVE) {
- close(finet);
- if ((ret = WEXITSTATUS(status)) != 0)
- return (ret);
- }
+
+ /* If we are the fullprop child in iprop mode, notify the parent
+ * process that it should poll for incremental updates. */
+ if (fullprop_child == 0)
+ kill(getppid(), SIGUSR1);
+ else if (runonce)
+ exit(0);
}
- if (iproprole == IPROP_SLAVE)
- break;
}
- return 0;
+ exit(0);
}
-void doit(fd)
- int fd;
+static void
+doit(int fd)
{
struct sockaddr_storage from;
int on = 1;
mode_t omask;
krb5_enctype etype;
int database_fd;
- char host[INET6_ADDRSTRLEN+1];
+ char host[INET6_ADDRSTRLEN + 1];
- if (kpropd_context->kdblog_context &&
- kpropd_context->kdblog_context->iproprole == IPROP_SLAVE) {
- /*
- * We also want to set a timer so that the slave is not waiting
- * until infinity for an update from the master.
- */
- if (debug)
- fprintf(stderr, "doit: setting resync alarm to 5s\n");
- signal(SIGALRM, resync_alarm);
- gfd = fd;
- if (alarm(INITIAL_TIMER) != 0) {
- if (debug) {
- fprintf(stderr,
- _("%s: alarm already set\n"), progname);
- }
- }
- }
- fromlen = sizeof (from);
- if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
+ signal_wrapper(SIGALRM, alarm_handler);
+ alarm(params.iprop_resync_timeout);
+ fromlen = sizeof(from);
+ if (getpeername(fd, (struct sockaddr *)&from, &fromlen) < 0) {
#ifdef ENOTSOCK
if (errno == ENOTSOCK && fd == 0 && !standalone) {
fprintf(stderr,
exit(1);
}
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on,
- sizeof (on)) < 0) {
+ sizeof(on)) < 0) {
com_err(progname, errno,
_("while attempting setsockopt (SO_KEEPALIVE)"));
}
host, sizeof(host), NULL, 0, 0) == 0) {
syslog(LOG_INFO, _("Connection from %s"), host);
if (debug)
- printf("Connection from %s\n", host);
+ fprintf(stderr, "Connection from %s\n", host);
}
/*
*/
kerberos_authenticate(kpropd_context, fd, &client, &etype, &from);
- /*
- * Turn off alarm upon successful authentication from master.
- */
- alarm(0);
- gfd = -1;
-
if (!authorized_principal(kpropd_context, client, etype)) {
- char *name;
+ char *name;
retval = krb5_unparse_name(kpropd_context, client, &name);
if (retval) {
- com_err(progname, retval,
- "While unparsing client name");
+ com_err(progname, retval, "While unparsing client name");
exit(1);
}
if (debug) {
exit(1);
}
omask = umask(077);
- lock_fd = open(temp_file_name, O_RDWR|O_CREAT, 0600);
- (void) umask(omask);
+ lock_fd = open(temp_file_name, O_RDWR | O_CREAT, 0600);
+ (void)umask(omask);
retval = krb5_lock_file(kpropd_context, lock_fd,
- KRB5_LOCKMODE_EXCLUSIVE|KRB5_LOCKMODE_DONTBLOCK);
+ KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK);
if (retval) {
com_err(progname, retval, _("while trying to lock '%s'"),
temp_file_name);
exit(1);
}
- if ((database_fd = open(temp_file_name,
- O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
+ database_fd = open(temp_file_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (database_fd < 0) {
com_err(progname, errno, _("while opening database file, '%s'"),
temp_file_name);
exit(1);
com_err(progname, retval, _("while unlocking '%s'"), temp_file_name);
exit(1);
}
- (void)close(lock_fd);
+ close(lock_fd);
/*
* Send the acknowledgement message generated in
* recv_database, then close the socket.
*/
- retval = krb5_write_message(kpropd_context, (void *) &fd, &confmsg);
+ retval = krb5_write_message(kpropd_context, &fd, &confmsg);
if (retval) {
krb5_free_data_contents(kpropd_context, &confmsg);
com_err(progname, retval, _("while sending # of received bytes"));
memset(&clnt_res, 0, sizeof(clnt_res));
- status = clnt_call (clnt, IPROP_FULL_RESYNC_EXT,
- (xdrproc_t) xdr_u_int32,
- (caddr_t) &vers,
- (xdrproc_t) xdr_kdb_fullresync_result_t,
- (caddr_t) &clnt_res,
- full_resync_timeout);
+ status = clnt_call(clnt, IPROP_FULL_RESYNC_EXT, (xdrproc_t)xdr_u_int32,
+ (caddr_t)&vers, (xdrproc_t)xdr_kdb_fullresync_result_t,
+ (caddr_t)&clnt_res, full_resync_timeout);
if (status == RPC_PROCUNAVAIL) {
- status = clnt_call (clnt, IPROP_FULL_RESYNC,
- (xdrproc_t) xdr_void,
- (caddr_t *)&vers,
- (xdrproc_t) xdr_kdb_fullresync_result_t,
- (caddr_t) &clnt_res,
- full_resync_timeout);
+ status = clnt_call(clnt, IPROP_FULL_RESYNC, (xdrproc_t)xdr_void,
+ (caddr_t *)&vers,
+ (xdrproc_t)xdr_kdb_fullresync_result_t,
+ (caddr_t)&clnt_res, full_resync_timeout);
}
return (status == RPC_SUCCESS) ? &clnt_res : NULL;
}
/*
- * Routine to handle incremental update transfer(s) from master KDC
+ * Beg for incrementals from the KDC.
+ *
+ * Returns 0 on success IFF runonce is true.
+ * Returns non-zero on failure due to errors.
*/
-kadm5_config_params params;
-krb5_error_code do_iprop(kdb_log_context *log_ctx)
+krb5_error_code
+do_iprop()
{
kadm5_ret_t retval;
- krb5_ccache cc;
krb5_principal iprop_svc_principal;
void *server_handle = NULL;
- char *iprop_svc_princstr = NULL;
- char *master_svc_princstr = NULL;
+ char *iprop_svc_princstr = NULL, *master_svc_princstr = NULL;
unsigned int pollin, backoff_time;
- int backoff_cnt = 0;
- int reinit_cnt = 0;
- int ret;
- int frdone = 0;
-
+ int backoff_cnt = 0, reinit_cnt = 0;
+ struct timeval iprop_start, iprop_end;
+ unsigned long usec;
+ time_t frrequested = 0, now;
kdb_incr_result_t *incr_ret;
- static kdb_last_t mylast;
-
+ kdb_last_t mylast;
kdb_fullresync_result_t *full_ret;
-
kadm5_iprop_handle_t handle;
- kdb_hlog_t *ulog;
- if (!debug)
- daemon(0, 0);
-
- ulog = log_ctx->ulog;
+ if (debug)
+ fprintf(stderr, _("Incremental propagation enabled\n"));
pollin = params.iprop_poll_time;
- if (pollin < 10)
+ if (pollin == 0)
pollin = 10;
- /*
- * Grab the realm info and check if iprop is enabled.
- */
- if (def_realm == NULL) {
- retval = krb5_get_default_realm(kpropd_context, &def_realm);
- if (retval) {
- com_err(progname, retval,
- _("Unable to get default realm"));
- exit(1);
- }
- }
-
- params.mask |= KADM5_CONFIG_REALM;
- params.realm = def_realm;
-
if (master_svc_princstr == NULL) {
- if ((retval = kadm5_get_kiprop_host_srv_name(kpropd_context,
- def_realm,
- &master_svc_princstr))) {
+ retval = kadm5_get_kiprop_host_srv_name(kpropd_context, realm,
+ &master_svc_princstr);
+ if (retval) {
com_err(progname, retval,
_("%s: unable to get kiprop host based "
"service name for realm %s\n"),
- progname, def_realm);
- exit(1);
+ progname, realm);
+ return retval;
}
}
- /*
- * Set cc to the default credentials cache
- */
- if ((retval = krb5_cc_default(kpropd_context, &cc))) {
- com_err(progname, retval,
- _("while opening default "
- "credentials cache"));
- exit(1);
- }
-
- retval = krb5_sname_to_principal(kpropd_context, NULL, KIPROP_SVC_NAME,
- KRB5_NT_SRV_HST, &iprop_svc_principal);
+ retval = sn2princ_realm(kpropd_context, NULL, KIPROP_SVC_NAME, realm,
+ &iprop_svc_principal);
if (retval) {
com_err(progname, retval,
_("while trying to construct host service principal"));
- exit(1);
+ return retval;
}
- /* XXX referrals? */
- if (krb5_is_referral_realm(krb5_princ_realm(kpropd_context,
- iprop_svc_principal))) {
- krb5_data *r = krb5_princ_realm(kpropd_context,
- iprop_svc_principal);
- assert(def_realm != NULL);
- r->length = strlen(def_realm);
- r->data = strdup(def_realm);
- if (r->data == NULL) {
- com_err(progname, retval,
- _("while determining local service principal name"));
- exit(1);
- }
- /* XXX Memory leak: Old r->data value. */
- }
- if ((retval = krb5_unparse_name(kpropd_context, iprop_svc_principal,
- &iprop_svc_princstr))) {
+ retval = krb5_unparse_name(kpropd_context, iprop_svc_principal,
+ &iprop_svc_princstr);
+ if (retval) {
com_err(progname, retval,
_("while canonicalizing principal name"));
krb5_free_principal(kpropd_context, iprop_svc_principal);
- exit(1);
+ return retval;
}
krb5_free_principal(kpropd_context, iprop_svc_principal);
/*
* Authentication, initialize rpcsec_gss handle etc.
*/
+ if (debug) {
+ fprintf(stderr, _("Initializing kadm5 as client %s\n"),
+ iprop_svc_princstr);
+ }
retval = kadm5_init_with_skey(kpropd_context, iprop_svc_princstr,
srvtab,
master_svc_princstr,
¶ms,
KADM5_STRUCT_VERSION,
- KADM5_API_VERSION_3,
+ KADM5_API_VERSION_4,
db_args,
&server_handle);
if (retval) {
+ if (debug)
+ fprintf(stderr, _("kadm5 initialization failed!\n"));
if (retval == KADM5_RPC_ERROR) {
reinit_cnt++;
if (server_handle)
- kadm5_destroy((void *) server_handle);
- server_handle = (void *)NULL;
- handle = (kadm5_iprop_handle_t)NULL;
+ kadm5_destroy(server_handle);
+ server_handle = NULL;
+ handle = NULL;
com_err(progname, retval, _(
"while attempting to connect"
" to master KDC ... retrying"));
backoff_time = backoff_from_master(&reinit_cnt);
- (void) sleep(backoff_time);
+ if (debug) {
+ fprintf(stderr, _("Sleeping %d seconds to re-initialize "
+ "kadm5 (RPC ERROR)\n"), backoff_time);
+ }
+ sleep(backoff_time);
goto reinit;
} else {
if (retval == KADM5_BAD_CLIENT_PARAMS ||
_("while initializing %s interface, retrying"),
progname);
backoff_time = backoff_from_master(&reinit_cnt);
+ if (debug) {
+ fprintf(stderr, _("Sleeping %d seconds to re-initialize "
+ "kadm5 (krb5kdc not running?)\n"),
+ backoff_time);
+ }
sleep(backoff_time);
goto reinit;
}
}
+ if (debug)
+ fprintf(stderr, _("kadm5 initialization succeeded\n"));
+
/*
* Reset re-initialization count to zero now.
*/
* Get the most recent ulog entry sno + ts, which
* we package in the request to the master KDC
*/
- mylast.last_sno = ulog->kdb_last_sno;
- mylast.last_time = ulog->kdb_last_time;
+ retval = ulog_get_last(kpropd_context, &mylast);
+ if (retval) {
+ com_err(progname, retval, _("reading update log header"));
+ goto done;
+ }
/*
* Loop continuously on an iprop_get_updates_1(),
* or (if needed) do a full resync of the krb5 db.
*/
+ if (debug) {
+ fprintf(stderr, _("Calling iprop_get_updates_1 "
+ "(sno=%u sec=%u usec=%u)\n"),
+ (unsigned int)mylast.last_sno,
+ (unsigned int)mylast.last_time.seconds,
+ (unsigned int)mylast.last_time.useconds);
+ }
+ gettimeofday(&iprop_start, NULL);
incr_ret = iprop_get_updates_1(&mylast, handle->clnt);
if (incr_ret == (kdb_incr_result_t *)NULL) {
clnt_perror(handle->clnt,
_("iprop_get_updates call failed"));
if (server_handle)
- kadm5_destroy((void *)server_handle);
- server_handle = (void *)NULL;
+ kadm5_destroy(server_handle);
+ server_handle = NULL;
handle = (kadm5_iprop_handle_t)NULL;
+ if (debug) {
+ fprintf(stderr, _("Reinitializing iprop because get updates "
+ "failed\n"));
+ }
goto reinit;
}
case UPDATE_FULL_RESYNC_NEEDED:
/*
- * We dont do a full resync again, if the last
- * X'fer was a resync and if the master sno is
- * still "0", i.e. no updates so far.
+ * If we're already asked for a full resync and we still
+ * need one and the last one hasn't timed out then just keep
+ * asking for updates as eventually the resync will finish
+ * (or, if it times out we'll just try again). Note that
+ * doit() also applies a timeout to the full resync, thus
+ * it's OK for us to do the same here.
*/
- if ((frdone == 1) && (incr_ret->lastentry.last_sno
- == 0)) {
+ now = time(NULL);
+ if (frrequested &&
+ (now - frrequested) < params.iprop_resync_timeout) {
+ if (debug)
+ fprintf(stderr, _("Still waiting for full resync\n"));
break;
} else {
+ frrequested = now;
+ if (debug)
+ fprintf(stderr, _("Full resync needed\n"));
+ syslog(LOG_INFO, _("kpropd: Full resync needed."));
+
full_ret = full_resync(handle->clnt);
- if (full_ret == (kdb_fullresync_result_t *)
- NULL) {
+ if (full_ret == NULL) {
clnt_perror(handle->clnt,
_("iprop_full_resync call failed"));
- if (server_handle)
- kadm5_destroy((void *)
- server_handle);
- server_handle = (void *)NULL;
- handle = (kadm5_iprop_handle_t)NULL;
+ kadm5_destroy(server_handle);
+ server_handle = NULL;
+ handle = NULL;
goto reinit;
}
}
switch (full_ret->ret) {
case UPDATE_OK:
+ if (debug)
+ fprintf(stderr, _("Full resync request granted\n"));
+ syslog(LOG_INFO, _("Full resync request granted."));
backoff_cnt = 0;
- /*
- * We now listen on the kprop port for
- * the full dump
- */
- ret = do_standalone(log_ctx->iproprole);
- if (debug) {
- if (ret)
- fprintf(stderr,
- _("Full resync "
- "was unsuccessful\n"));
- else
- fprintf(stderr,
- _("Full resync "
- "was successful\n"));
- }
- if (ret) {
- syslog(LOG_WARNING,
- _("kpropd: Full resync, invalid return."));
- frdone = 0;
- backoff_cnt++;
- } else
- frdone = 1;
break;
case UPDATE_BUSY:
/*
* Exponential backoff
*/
+ if (debug)
+ fprintf(stderr, _("Exponential backoff\n"));
backoff_cnt++;
break;
- case UPDATE_FULL_RESYNC_NEEDED:
- case UPDATE_NIL:
- default:
- backoff_cnt = 0;
- frdone = 0;
- syslog(LOG_ERR, _("kpropd: Full resync,"
- " invalid return from master KDC."));
- break;
-
case UPDATE_PERM_DENIED:
- syslog(LOG_ERR, _("kpropd: Full resync,"
- " permission denied."));
+ if (debug)
+ fprintf(stderr, _("Full resync permission denied\n"));
+ syslog(LOG_ERR, _("Full resync, permission denied."));
goto error;
case UPDATE_ERROR:
- syslog(LOG_ERR, _("kpropd: Full resync,"
- " error returned from master KDC."));
+ if (debug)
+ fprintf(stderr, _("Full resync error from master\n"));
+ syslog(LOG_ERR, _(" Full resync, "
+ "error returned from master KDC."));
goto error;
+
+ default:
+ backoff_cnt = 0;
+ if (debug) {
+ fprintf(stderr,
+ _("Full resync invalid result from master\n"));
+ }
+ syslog(LOG_ERR, _("Full resync, "
+ "invalid return from master KDC."));
+ break;
}
break;
case UPDATE_OK:
backoff_cnt = 0;
- frdone = 0;
+ frrequested = 0;
/*
* ulog_replay() will convert the ulog updates to db
* entries using the kdb conv api and will commit
* the entries to the slave kdc database
*/
- retval = ulog_replay(kpropd_context, incr_ret,
- db_args);
+ if (debug) {
+ fprintf(stderr, _("Got incremental updates "
+ "(sno=%u sec=%u usec=%u)\n"),
+ (unsigned int)incr_ret->lastentry.last_sno,
+ (unsigned int)incr_ret->lastentry.last_time.seconds,
+ (unsigned int)incr_ret->lastentry.last_time.useconds);
+ }
+ retval = ulog_replay(kpropd_context, incr_ret, db_args);
if (retval) {
const char *msg =
krb5_get_error_message(kpropd_context, retval);
- syslog(LOG_ERR,
- _("kpropd: ulog_replay failed (%s), updates not registered."), msg);
+ if (debug) {
+ fprintf(stderr, _("ulog_replay failed (%s), updates not "
+ "registered\n"), msg);
+ }
+ syslog(LOG_ERR, _("ulog_replay failed (%s), updates "
+ "not registered."), msg);
krb5_free_error_message(kpropd_context, msg);
break;
}
- if (debug)
- fprintf(stderr, _("Update transfer "
- "from master was OK\n"));
+ gettimeofday(&iprop_end, NULL);
+ usec = (iprop_end.tv_sec - iprop_start.tv_sec) * 1000000 +
+ iprop_end.tv_usec - iprop_start.tv_usec;
+ syslog(LOG_INFO, _("Incremental updates: %d updates / %lu us"),
+ incr_ret->updates.kdb_ulog_t_len, usec);
+ if (debug) {
+ fprintf(stderr, _("Incremental updates: %d updates / "
+ "%lu us\n"),
+ incr_ret->updates.kdb_ulog_t_len, usec);
+ }
break;
case UPDATE_PERM_DENIED:
- syslog(LOG_ERR, _("kpropd: get_updates,"
- " permission denied."));
+ if (debug)
+ fprintf(stderr, _("get_updates permission denied\n"));
+ syslog(LOG_ERR, _("get_updates, permission denied."));
goto error;
case UPDATE_ERROR:
- syslog(LOG_ERR, _("kpropd: get_updates, error "
- "returned from master KDC."));
+ if (debug)
+ fprintf(stderr, _("get_updates error from master\n"));
+ syslog(LOG_ERR, _("get_updates, error returned from master KDC."));
goto error;
case UPDATE_BUSY:
/*
* Exponential backoff
*/
+ if (debug)
+ fprintf(stderr, _("get_updates master busy; backoff\n"));
backoff_cnt++;
break;
* Master-slave are in sync
*/
if (debug)
- fprintf(stderr, _("Master, slave KDC's "
- "are in-sync, no updates\n"));
+ fprintf(stderr, _("KDC is synchronized with master.\n"));
backoff_cnt = 0;
- frdone = 0;
+ frrequested = 0;
break;
default:
backoff_cnt = 0;
- syslog(LOG_ERR, _("kpropd: get_updates,"
- " invalid return from master KDC."));
+ if (debug)
+ fprintf(stderr, _("get_updates invalid result from master\n"));
+ syslog(LOG_ERR, _("get_updates, invalid return from master KDC."));
break;
}
- if (runonce == 1)
+ if (runonce == 1 && incr_ret->ret != UPDATE_FULL_RESYNC_NEEDED)
goto done;
/*
*/
if (backoff_cnt > 0) {
backoff_time = backoff_from_master(&backoff_cnt);
- if (debug)
+ if (debug) {
fprintf(stderr, _("Busy signal received "
"from master, backoff for %d secs\n"),
backoff_time);
- (void) sleep(backoff_time);
+ }
+ sleep(backoff_time);
+ } else {
+ if (debug) {
+ fprintf(stderr, _("Waiting for %d seconds before checking "
+ "for updates again\n"), pollin);
+ }
+ sleep(pollin);
}
- else
- (void) sleep(pollin);
}
error:
if (debug)
fprintf(stderr, _("ERROR returned by master, bailing\n"));
- syslog(LOG_ERR, _("kpropd: ERROR returned by master KDC,"
- " bailing.\n"));
+ syslog(LOG_ERR, _("ERROR returned by master KDC, bailing.\n"));
done:
- if(iprop_svc_princstr)
- free(iprop_svc_princstr);
- if (master_svc_princstr)
- free(master_svc_princstr);
- if ((retval = krb5_cc_close(kpropd_context, cc))) {
- com_err(progname, retval,
- _("while closing default ccache"));
- exit(1);
- }
- if (def_realm && kpropd_context)
- krb5_free_default_realm(kpropd_context, def_realm);
- if (server_handle)
- kadm5_destroy((void *)server_handle);
- if (kpropd_context)
- krb5_free_context(kpropd_context);
-
- if (runonce == 1)
- return (0);
- else
- exit(1);
+ free(iprop_svc_princstr);
+ free(master_svc_princstr);
+ krb5_free_default_realm(kpropd_context, def_realm);
+ kadm5_destroy(server_handle);
+ krb5_db_fini(kpropd_context);
+ ulog_fini(kpropd_context);
+ krb5_free_context(kpropd_context);
+
+ return (runonce == 1) ? 0 : 1;
}
-/*
- * Do exponential backoff, since master KDC is BUSY or down
- */
-unsigned int backoff_from_master(int *cnt) {
+/* Do exponential backoff, since master KDC is BUSY or down. */
+static unsigned int
+backoff_from_master(int *cnt)
+{
unsigned int btime;
btime = (unsigned int)(2<<(*cnt));
(*cnt)--;
}
- return (btime);
+ return btime;
}
static void
-kpropd_com_err_proc(const char *whoami,
- long code,
- const char *fmt,
+kpropd_com_err_proc(const char *whoami, long code, const char *fmt,
va_list args)
#if !defined(__cplusplus) && (__GNUC__ > 2)
__attribute__((__format__(__printf__, 3, 0)))
;
static void
-kpropd_com_err_proc(const char *whoami,
- long code,
- const char *fmt,
+kpropd_com_err_proc(const char *whoami, long code, const char *fmt,
va_list args)
{
- char error_buf[8096];
+ char error_buf[8096];
error_buf[0] = '\0';
if (fmt)
code ? error_message(code) : "", code ? " " : "", error_buf);
}
-void PRS(argv)
- char **argv;
+static void
+parse_args(char **argv)
{
- register char *word, ch;
+ char **newargs, *word, ch;
krb5_error_code retval;
- static const char tmp[] = ".temp";
- kdb_log_context *log_ctx;
- (void) memset(¶ms, 0, sizeof (params));
+ memset(¶ms, 0, sizeof(params));
/* Since we may modify the KDB with ulog_replay(), we must read the KDC
* profile. */
}
progname = *argv++;
- while ((word = *argv++)) {
- if (*word == '-') {
- word++;
- while (word && (ch = *word++)) {
- switch(ch){
- case 'f':
- if (*word)
- file = word;
- else
- file = *argv++;
- if (!file)
- usage();
- word = 0;
- break;
- case 'F':
- if (*word)
- kerb_database = word;
- else
- kerb_database = *argv++;
- if (!kerb_database)
- usage();
- word = 0;
- break;
- case 'p':
- if (*word)
- kdb5_util = word;
- else
- kdb5_util = *argv++;
- if (!kdb5_util)
- usage();
- word = 0;
- break;
- case 'P':
- port = (*word != '\0') ? word : *argv++;
- if (port == NULL)
- usage();
- word = 0;
- break;
- case 'r':
- if (*word)
- realm = word;
- else
- realm = *argv++;
- if (!realm)
- usage();
- word = 0;
- break;
- case 's':
- if (*word)
- srvtab = word;
- else
- srvtab = *argv++;
- if (!srvtab)
- usage();
- word = 0;
- break;
- case 'd':
- debug++;
- break;
- case 'S':
- standalone++;
- break;
- case 'a':
- if (*word)
- acl_file_name = word;
- else
- acl_file_name = *argv++;
- if (!acl_file_name)
- usage();
- word = 0;
- break;
-
- case 't':
- /*
- * Undocumented option - for testing only.
- *
- * Option to run the kpropd server exactly
- * once (this is true only if iprop is enabled).
- */
- runonce = 1;
- break;
-
- case 'x':
- {
- char **new_db_args;
- new_db_args = realloc(db_args,
- (db_args_size+2)*sizeof(*db_args));
- if (new_db_args == NULL) {
- com_err(argv[0], errno, _("copying db args"));
- exit(1);
- }
- db_args = new_db_args;
- if (*word)
- db_args[db_args_size] = word;
- else
- db_args[db_args_size] = *argv++;
- word = 0;
- if (db_args[db_args_size] == NULL)
- usage();
- db_args[db_args_size+1] = NULL;
- db_args_size++;
- }
+ while ((word = *argv++) != NULL) {
+ /* We don't take any arguments, only options */
+ if (*word != '-')
+ usage();
- default:
+ word++;
+ while (word != NULL && (ch = *word++) != '\0') {
+ switch (ch) {
+ case 'A':
+ params.mask |= KADM5_CONFIG_ADMIN_SERVER;
+ params.admin_server = (*word != '\0') ? word : *argv++;
+ if (params.admin_server == NULL)
usage();
+ word = NULL;
+ break;
+ case 'f':
+ file = (*word != '\0') ? word : *argv++;
+ if (file == NULL)
+ usage();
+ word = NULL;
+ break;
+ case 'F':
+ kerb_database = (*word != '\0') ? word : *argv++;
+ if (kerb_database == NULL)
+ usage();
+ word = NULL;
+ break;
+ case 'p':
+ kdb5_util = (*word != '\0') ? word : *argv++;
+ if (kdb5_util == NULL)
+ usage();
+ word = NULL;
+ break;
+ case 'P':
+ port = (*word != '\0') ? word : *argv++;
+ if (port == NULL)
+ usage();
+ word = NULL;
+ break;
+ case 'r':
+ realm = (*word != '\0') ? word : *argv++;
+ if (realm == NULL)
+ usage();
+ word = NULL;
+ break;
+ case 's':
+ srvtab = (*word != '\0') ? word : *argv++;
+ if (srvtab == NULL)
+ usage();
+ word = NULL;
+ break;
+ case 'D':
+ nodaemon++;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'S':
+ /* Standalone mode is now auto-detected; see main(). */
+ break;
+ case 'a':
+ acl_file_name = (*word != '\0') ? word : *argv++;
+ if (acl_file_name == NULL)
+ usage();
+ word = NULL;
+ break;
+
+ case 't':
+ /* Undocumented option - for testing only. Run the kpropd
+ * server exactly once. */
+ runonce = 1;
+ break;
+
+ case 'x':
+ newargs = realloc(db_args,
+ (db_args_size + 2) * sizeof(*db_args));
+ if (newargs == NULL) {
+ com_err(argv[0], errno, _("copying db args"));
+ exit(1);
}
+ db_args = newargs;
+ db_args[db_args_size] = (*word != '\0') ? word : *argv++;
+ if (db_args[db_args_size] == NULL)
+ usage();
+ word = NULL;
+ db_args[db_args_size + 1] = NULL;
+ db_args_size++;
+ break;
+ default:
+ usage();
}
- } else
- /* We don't take any arguments, only options */
- usage();
+ }
}
- /*
- * If not in debug mode, switch com_err reporting to syslog
- */
- if (! debug) {
- openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
+
+ openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
+ if (!debug)
set_com_err_hook(kpropd_com_err_proc);
+
+ if (realm == NULL) {
+ retval = krb5_get_default_realm(kpropd_context, &def_realm);
+ if (retval) {
+ com_err(progname, retval, _("Unable to get default realm"));
+ exit(1);
+ }
+ realm = def_realm;
+ } else {
+ retval = krb5_set_default_realm(kpropd_context, realm);
+ if (retval) {
+ com_err(progname, retval, _("Unable to set default realm"));
+ exit(1);
+ }
}
- /*
- * Get my hostname, so we can construct my service name
- */
- retval = krb5_sname_to_principal(kpropd_context,
- NULL, KPROP_SERVICE_NAME,
- KRB5_NT_SRV_HST, &server);
+
+ /* Construct service name from local hostname. */
+ retval = sn2princ_realm(kpropd_context, NULL, KPROP_SERVICE_NAME, realm,
+ &server);
if (retval) {
com_err(progname, retval,
_("while trying to construct my service name"));
exit(1);
}
- if (realm) {
- retval = krb5_set_principal_realm(kpropd_context, server, realm);
- if (retval) {
- com_err(progname, errno,
- _("while constructing my service realm"));
- exit(1);
- }
- }
- /*
- * Construct the name of the temporary file.
- */
- if (asprintf(&temp_file_name, "%s%s", file, tmp) < 0) {
+
+ /* Construct the name of the temporary file. */
+ if (asprintf(&temp_file_name, "%s.temp", file) < 0) {
com_err(progname, ENOMEM,
_("while allocating filename for temp file"));
exit(1);
}
+ params.realm = realm;
+ params.mask |= KADM5_CONFIG_REALM;
retval = kadm5_get_config_params(kpropd_context, 1, ¶ms, ¶ms);
if (retval) {
com_err(progname, retval, _("while initializing"));
ulog_set_role(kpropd_context, IPROP_SLAVE);
if (ulog_map(kpropd_context, params.iprop_logfile,
- params.iprop_ulogsize, FKPROPD, db_args)) {
- com_err(progname, errno,
- _("Unable to map log!\n"));
+ params.iprop_ulogsize)) {
+ com_err(progname, errno, _("Unable to map log!\n"));
exit(1);
}
}
- log_ctx = kpropd_context->kdblog_context;
- if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE))
- ulog_set_role(kpropd_context, IPROP_SLAVE);
}
/*
* Figure out who's calling on the other end of the connection....
*/
-void
-kerberos_authenticate(context, fd, clientp, etype, my_sin)
- krb5_context context;
- int fd;
- krb5_principal * clientp;
- krb5_enctype * etype;
- struct sockaddr_storage * my_sin;
+static void
+kerberos_authenticate(krb5_context context, int fd, krb5_principal *clientp,
+ krb5_enctype *etype, struct sockaddr_storage *my_sin)
{
- krb5_error_code retval;
- krb5_ticket * ticket;
- struct sockaddr_storage r_sin;
+ krb5_error_code retval;
+ krb5_ticket *ticket;
+ struct sockaddr_storage r_sin;
GETSOCKNAME_ARG3_TYPE sin_length;
- krb5_keytab keytab = NULL;
+ krb5_keytab keytab = NULL;
+ char *name, etypebuf[100];
- /*
- * Set recv_addr and send_addr
- */
- sockaddr2krbaddr(context, my_sin->ss_family, (struct sockaddr *) my_sin,
+ /* Set recv_addr and send_addr. */
+ sockaddr2krbaddr(context, my_sin->ss_family, (struct sockaddr *)my_sin,
&sender_addr);
sin_length = sizeof(r_sin);
- if (getsockname(fd, (struct sockaddr *) &r_sin, &sin_length)) {
+ if (getsockname(fd, (struct sockaddr *)&r_sin, &sin_length)) {
com_err(progname, errno, _("while getting local socket address"));
exit(1);
}
- sockaddr2krbaddr(context, r_sin.ss_family, (struct sockaddr *) &r_sin,
+ sockaddr2krbaddr(context, r_sin.ss_family, (struct sockaddr *)&r_sin,
&receiver_addr);
if (debug) {
- char *name;
-
retval = krb5_unparse_name(context, server, &name);
if (retval) {
com_err(progname, retval, _("while unparsing client name"));
exit(1);
}
- printf("krb5_recvauth(%d, %s, %s, ...)\n", fd, kprop_version, name);
+ fprintf(stderr, "krb5_recvauth(%d, %s, %s, ...)\n", fd, kprop_version,
+ name);
free(name);
}
exit(1);
}
- if (srvtab) {
+ if (srvtab != NULL) {
retval = krb5_kt_resolve(context, srvtab, &keytab);
if (retval) {
syslog(LOG_ERR, _("Error in krb5_kt_resolve: %s"),
}
}
- retval = krb5_recvauth(context, &auth_context, (void *) &fd,
- kprop_version, server, 0, keytab, &ticket);
+ retval = krb5_recvauth(context, &auth_context, &fd, kprop_version, server,
+ 0, keytab, &ticket);
if (retval) {
syslog(LOG_ERR, _("Error in krb5_recvauth: %s"),
error_message(retval));
*etype = ticket->enc_part.enctype;
if (debug) {
- char * name;
- char etypebuf[100];
-
retval = krb5_unparse_name(context, *clientp, &name);
if (retval) {
com_err(progname, retval, _("while unparsing client name"));
exit(1);
}
- printf(_("authenticated client: %s (etype == %s)\n"), name, etypebuf);
+ fprintf(stderr, _("authenticated client: %s (etype == %s)\n"),
+ name, etypebuf);
free(name);
}
krb5_free_ticket(context, ticket);
}
-krb5_boolean
-authorized_principal(context, p, auth_etype)
- krb5_context context;
- krb5_principal p;
- krb5_enctype auth_etype;
+static krb5_boolean
+authorized_principal(krb5_context context, krb5_principal p,
+ krb5_enctype auth_etype)
{
- char *name, *ptr;
- char buf[1024];
- krb5_error_code retval;
- FILE *acl_file;
- int end;
- krb5_enctype acl_etype;
+ char *name, *ptr, buf[1024];
+ krb5_error_code retval;
+ FILE *acl_file;
+ int end;
+ krb5_enctype acl_etype;
retval = krb5_unparse_name(context, p, &name);
if (retval)
return FALSE;
acl_file = fopen(acl_file_name, "r");
- if (!acl_file)
+ if (acl_file == NULL)
return FALSE;
while (!feof(acl_file)) {
if (buf[end] == '\n')
buf[end] = '\0';
if (!strncmp(name, buf, strlen(name))) {
- ptr = buf+strlen(name);
+ ptr = buf + strlen(name);
- /* if the next character is not whitespace or nul, then
- the match is only partial. continue on to new lines. */
- if (*ptr && !isspace((int) *ptr))
+ /* If the next character is not whitespace or null, then the match
+ * is only partial. Continue on to new lines. */
+ if (*ptr != '\0' && !isspace((int)*ptr))
continue;
- /* otherwise, skip trailing whitespace */
- for (; *ptr && isspace((int) *ptr); ptr++) ;
-
- /* now, look for an etype string. if there isn't one,
- return true. if there is an invalid string, continue.
- If there is a valid string, return true only if it
- matches the etype passed in, otherwise continue */
+ /* Otherwise, skip trailing whitespace. */
+ for (; *ptr != '\0' && isspace((int)*ptr); ptr++) ;
- if ((*ptr) &&
+ /*
+ * Now, look for an etype string. If there isn't one, return true.
+ * If there is an invalid string, continue. If there is a valid
+ * string, return true only if it matches the etype passed in,
+ * otherwise continue.
+ */
+ if (*ptr != '\0' &&
((retval = krb5_string_to_enctype(ptr, &acl_etype)) ||
(acl_etype != auth_etype)))
continue;
return FALSE;
}
-void
-recv_database(context, fd, database_fd, confmsg)
- krb5_context context;
- int fd;
- int database_fd;
- krb5_data *confmsg;
+static void
+recv_database(krb5_context context, int fd, int database_fd,
+ krb5_data *confmsg)
{
- krb5_ui_4 database_size; /* This must be 4 bytes */
- int received_size, n;
- char buf[1024];
- krb5_data inbuf, outbuf;
+ krb5_ui_4 database_size, received_size;
+ int n;
+ char buf[1024];
+ krb5_data inbuf, outbuf;
krb5_error_code retval;
- /*
- * Receive and decode size from client
- */
- retval = krb5_read_message(context, (void *) &fd, &inbuf);
+ /* Receive and decode size from client. */
+ retval = krb5_read_message(context, &fd, &inbuf);
if (retval) {
send_error(context, fd, retval, "while reading database size");
com_err(progname, retval,
recv_error(context, &inbuf);
retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL);
if (retval) {
- send_error(context, fd, retval,
- "while decoding database size");
+ send_error(context, fd, retval, "while decoding database size");
krb5_free_data_contents(context, &inbuf);
com_err(progname, retval,
_("while decoding database size from client"));
krb5_free_data_contents(context, &outbuf);
database_size = ntohl(database_size);
- /*
- * Initialize the initial vector.
- */
+ /* Initialize the initial vector. */
retval = krb5_auth_con_initivector(context, auth_context);
if (retval) {
send_error(context, fd, retval,
exit(1);
}
- /*
- * Now start receiving the database from the net
- */
+ if (debug)
+ fprintf(stderr, _("Full propagation transfer started.\n"));
+
+ /* Now start receiving the database from the net. */
received_size = 0;
while (received_size < database_size) {
- retval = krb5_read_message(context, (void *) &fd, &inbuf);
+ retval = krb5_read_message(context, &fd, &inbuf);
if (retval) {
snprintf(buf, sizeof(buf),
"while reading database block starting at offset %d",
}
if (krb5_is_krb_error(&inbuf))
recv_error(context, &inbuf);
- retval = krb5_rd_priv(context, auth_context, &inbuf,
- &outbuf, NULL);
+ retval = krb5_rd_priv(context, auth_context, &inbuf, &outbuf, NULL);
if (retval) {
snprintf(buf, sizeof(buf),
"while decoding database block starting at offset %d",
"while writing database block starting at offset %d",
received_size);
send_error(context, fd, errno, buf);
- } else if (n != outbuf.length) {
+ } else if ((unsigned int)n != outbuf.length) {
snprintf(buf, sizeof(buf),
- "incomplete write while writing database block starting at \noffset %d (%d written, %d expected)",
+ "incomplete write while writing database block starting "
+ "at \noffset %d (%d written, %d expected)",
received_size, n, outbuf.length);
send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
}
received_size += outbuf.length;
}
- /*
- * OK, we've seen the entire file. Did we get too many bytes?
- */
+
+ /* OK, we've seen the entire file. Did we get too many bytes? */
if (received_size > database_size) {
snprintf(buf, sizeof(buf),
"Received %d bytes, expected %d bytes for database file",
received_size, database_size);
send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
}
- /*
- * Create message acknowledging number of bytes received, but
- * don't send it until kdb5_util returns successfully.
- */
+
+ if (debug)
+ fprintf(stderr, _("Full propagation transfer finished.\n"));
+
+ /* Create message acknowledging number of bytes received, but
+ * don't send it until kdb5_util returns successfully. */
database_size = htonl(database_size);
- inbuf.data = (char *) &database_size;
+ inbuf.data = (char *)&database_size;
inbuf.length = sizeof(database_size);
retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL);
if (retval) {
- com_err(progname, retval,
- "while encoding # of receieved bytes");
- send_error(context, fd, retval,
- "while encoding # of received bytes");
+ com_err(progname, retval, "while encoding # of receieved bytes");
+ send_error(context, fd, retval, "while encoding # of received bytes");
exit(1);
}
}
-void
-send_error(context, fd, err_code, err_text)
- krb5_context context;
- int fd;
- krb5_error_code err_code;
- char *err_text;
+static void
+send_error(krb5_context context, int fd, krb5_error_code err_code,
+ char *err_text)
{
- krb5_error error;
- const char *text;
- krb5_data outbuf;
- char buf[1024];
+ krb5_error error;
+ const char *text;
+ krb5_data outbuf;
+ char buf[1024];
memset(&error, 0, sizeof(error));
krb5_us_timeofday(context, &error.stime, &error.susec);
error.server = server;
error.client = client;
- if (err_text)
- text = err_text;
- else
- text = error_message(err_code);
+ text = (err_text != NULL) ? err_text : error_message(err_code);
error.error = err_code - ERROR_TABLE_BASE_krb5;
if (error.error > 127) {
error.error = KRB_ERR_GENERIC;
if (err_text) {
- snprintf(buf, sizeof(buf), "%s %s",
- error_message(err_code), err_text);
+ snprintf(buf, sizeof(buf), "%s %s", error_message(err_code),
+ err_text);
text = buf;
}
}
error.text.data = strdup(text);
if (error.text.data) {
if (!krb5_mk_error(context, &error, &outbuf)) {
- (void) krb5_write_message(context, (void *)&fd,&outbuf);
+ (void)krb5_write_message(context, &fd, &outbuf);
krb5_free_data_contents(context, &outbuf);
}
free(error.text.data);
}
void
-recv_error(context, inbuf)
- krb5_context context;
- krb5_data *inbuf;
+recv_error(krb5_context context, krb5_data *inbuf)
{
- krb5_error *error;
+ krb5_error *error;
krb5_error_code retval;
retval = krb5_rd_error(context, inbuf, &error);
fprintf(stderr, _("Generic remote error: %s\n"), error->text.data);
} else if (error->error) {
com_err(progname,
- (krb5_error_code) error->error + ERROR_TABLE_BASE_krb5,
+ (krb5_error_code)error->error + ERROR_TABLE_BASE_krb5,
_("signaled from server"));
if (error->text.data) {
fprintf(stderr, _("Error text from client: %s\n"),
exit(1);
}
-void
-load_database(context, kdb_util, database_file_name)
- krb5_context context;
- char *kdb_util;
- char *database_file_name;
+static void
+load_database(krb5_context context, char *kdb_util, char *database_file_name)
{
- static char *edit_av[10];
- int error_ret, save_stderr = -1;
- int child_pid;
- int count;
+ static char *edit_av[10];
+ int error_ret, child_pid, count;
/* <sys/param.h> has been included, so BSD will be defined on
- BSD systems */
+ * BSD systems. */
#if BSD > 0 && BSD <= 43
#ifndef WEXITSTATUS
#define WEXITSTATUS(w) (w).w_retcode
#endif
- union wait waitb;
+ union wait waitb;
#else
- int waitb;
+ int waitb;
#endif
- krb5_error_code retval;
kdb_log_context *log_ctx;
if (debug)
- printf("calling kdb5_util to load database\n");
+ fprintf(stderr, "calling kdb5_util to load database\n");
log_ctx = context->kdblog_context;
edit_av[count++] = "-d";
edit_av[count++] = kerb_database;
}
- if (log_ctx && log_ctx->iproprole == IPROP_SLAVE) {
+ if (log_ctx && log_ctx->iproprole == IPROP_SLAVE)
edit_av[count++] = "-i";
- }
edit_av[count++] = database_file_name;
edit_av[count++] = NULL;
- switch(child_pid = fork()) {
+ switch (child_pid = fork()) {
case -1:
com_err(progname, errno, _("while trying to fork %s"), kdb_util);
exit(1);
case 0:
- if (!debug) {
- save_stderr = dup(2);
- close(0);
- close(1);
- close(2);
- open("/dev/null", O_RDWR);
- dup(0);
- dup(0);
- }
-
- if (execv(kdb_util, edit_av) < 0)
- retval = errno;
- else
- retval = 0;
- if (!debug)
- dup2(save_stderr, 2);
- com_err(progname, retval, _("while trying to exec %s"), kdb_util);
+ execv(kdb_util, edit_av);
+ com_err(progname, errno, _("while trying to exec %s"), kdb_util);
_exit(1);
/*NOTREACHED*/
default:
if (debug)
- printf("Child PID is %d\n", child_pid);
+ fprintf(stderr, "Load PID is %d\n", child_pid);
if (wait(&waitb) < 0) {
com_err(progname, errno, _("while waiting for %s"), kdb_util);
exit(1);
}
}
+ if (!WIFEXITED(waitb)) {
+ com_err(progname, 0, _("%s load terminated"), kdb_util);
+ exit(1);
+ }
+
error_ret = WEXITSTATUS(waitb);
if (error_ret) {
com_err(progname, 0, _("%s returned a bad exit status (%d)"),
* for host_service_name.
*/
static kadm5_ret_t
-kadm5_get_kiprop_host_srv_name(krb5_context context,
- const char *realm_name,
+kadm5_get_kiprop_host_srv_name(krb5_context context, const char *realm_name,
char **host_service_name)
{
- char *name;
- char *host;
+ char *name, *host;
host = params.admin_server; /* XXX */
-
if (asprintf(&name, "%s/%s", KADM5_KIPROP_HOST_SERVICE, host) < 0) {
free(host);
- return (ENOMEM);
+ return ENOMEM;
}
*host_service_name = name;
- return (KADM5_OK);
+ return KADM5_OK;
}