krb5 commit: Improve kpropd behavior in iprop mode
Greg Hudson
ghudson at MIT.EDU
Fri Oct 5 13:52:31 EDT 2012
https://github.com/krb5/krb5/commit/f1c85fbb0ab9e62b2790647b2681aec4d5fa4585
commit f1c85fbb0ab9e62b2790647b2681aec4d5fa4585
Author: Nicolas Williams <nico at cryptonector.com>
Date: Mon Sep 24 21:09:17 2012 -0500
Improve kpropd behavior in iprop mode
- Make kpropd in iprop mode fork a child to listen for kprops from the
master. The child writes progress and outcome reports to the parent
for each kprop. This fixes a race between asking for a full resync
and setting up a listener socket for it.
- Add runonce (-t) for kpropd do_standalone() too.
- Add a new iprop parameter: iprop_resync_timeout. kpropd will keep
asking for incremental updates while waiting for a full resync to
finish, and will re-request a full resync if kadmind continues to
indicate that one is needed after this timeout passes since the
previous full resync was requested.
- Allow polling intervals less than 10 seconds.
[ghudson at mit.edu: split out debug output changes; note polling interval
change in commit message]
ticket: 7373
doc/rst_source/krb_admins/conf_files/kdc_conf.rst | 6 +
doc/rst_source/krb_admins/database.rst | 1 +
src/include/k5-int.h | 1 +
src/lib/kadm5/admin.h | 2 +
src/lib/kadm5/alt_prof.c | 4 +
src/slave/kpropd.c | 396 +++++++++------------
6 files changed, 188 insertions(+), 222 deletions(-)
diff --git a/doc/rst_source/krb_admins/conf_files/kdc_conf.rst b/doc/rst_source/krb_admins/conf_files/kdc_conf.rst
index 54b0e41..7ded12d 100644
--- a/doc/rst_source/krb_admins/conf_files/kdc_conf.rst
+++ b/doc/rst_source/krb_admins/conf_files/kdc_conf.rst
@@ -206,6 +206,12 @@ For each realm, the following tags may be specified:
incremental propagation. This is required in both master and
slave configuration files.
+**iprop_resync_timeout**
+ (Delta time string.) Specifies the amount of time to wait for a
+ full propagation to complete. This is optional in configuration
+ files, and is used by slave KDCs only. The default value is 5
+ minutes (``5m``).
+
**iprop_logfile**
(File name.) Specifies where the update log file for the realm
database is to be stored. The default is to use the
diff --git a/doc/rst_source/krb_admins/database.rst b/doc/rst_source/krb_admins/database.rst
index eae37c8..afea975 100644
--- a/doc/rst_source/krb_admins/database.rst
+++ b/doc/rst_source/krb_admins/database.rst
@@ -701,6 +701,7 @@ iprop_enable *boolean* If *true*, then incremental propagation i
iprop_master_ulogsize *integer* Indicates the number of entries that should be retained in the update log. The default is 1000; the maximum number is 2500.
iprop_slave_poll *time interval* Indicates how often the slave should poll the master KDC for changes to the database. The default is two minutes.
iprop_port *integer* Specifies the port number to be used for incremental propagation. This is required in both master and slave configuration files.
+iprop_resync_timeout *integer* Specifies the number of seconds to wait for a full propagation to complete. This is optional on slave configurations. Defaults to 300 seconds (5 minutes).
iprop_logfile *file name* Specifies where the update log file for the realm database is to be stored. The default is to use the *database_name* entry from the realms section of the config file :ref:`kdc.conf(5)`, with *.ulog* appended. (NOTE: If database_name isn't specified in the realms section, perhaps because the LDAP database back end is being used, or the file name is specified in the *dbmodules* section, then the hard-coded default for *database_name* is used. Determination of the *iprop_logfile* default value will not use values from the *dbmodules* section.)
====================== =============== ===========================================
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index bf36a17..14123a6 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -224,6 +224,7 @@ typedef INT64_TYPE krb5_int64;
#define KRB5_CONF_IPROP_PORT "iprop_port"
#define KRB5_CONF_IPROP_SLAVE_POLL "iprop_slave_poll"
#define KRB5_CONF_IPROP_LOGFILE "iprop_logfile"
+#define KRB5_CONF_IPROP_RESYNC_TIMEOUT "iprop_resync_timeout"
#define KRB5_CONF_K5LOGIN_AUTHORITATIVE "k5login_authoritative"
#define KRB5_CONF_K5LOGIN_DIRECTORY "k5login_directory"
#define KRB5_CONF_KADMIND_PORT "kadmind_port"
diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h
index 037e2f9..9260cb5 100644
--- a/src/lib/kadm5/admin.h
+++ b/src/lib/kadm5/admin.h
@@ -164,6 +164,7 @@ typedef long kadm5_ret_t;
#define KADM5_CONFIG_IPROP_LOGFILE 0x08000000
#define KADM5_CONFIG_IPROP_PORT 0x10000000
#define KADM5_CONFIG_KVNO 0x20000000
+#define KADM5_CONFIG_IPROP_RESYNC_TIMEOUT 0x40000000
/*
* permission bits
*/
@@ -274,6 +275,7 @@ typedef struct _kadm5_config_params {
char * iprop_logfile;
/* char * iprop_server;*/
int iprop_port;
+ int iprop_resync_timeout;
} kadm5_config_params;
/***********************************************************************
diff --git a/src/lib/kadm5/alt_prof.c b/src/lib/kadm5/alt_prof.c
index 2198cd1..769f5f9 100644
--- a/src/lib/kadm5/alt_prof.c
+++ b/src/lib/kadm5/alt_prof.c
@@ -802,6 +802,10 @@ krb5_error_code kadm5_get_config_params(context, use_kdc_config,
GET_PORT_PARAM(iprop_port, KADM5_CONFIG_IPROP_PORT,
KRB5_CONF_IPROP_PORT, 0);
+ /* 5 min for large KDBs */
+ GET_DELTAT_PARAM(iprop_resync_timeout, KADM5_CONFIG_IPROP_RESYNC_TIMEOUT,
+ KRB5_CONF_IPROP_RESYNC_TIMEOUT, 60 * 5);
+
hierarchy[2] = KRB5_CONF_IPROP_MASTER_ULOGSIZE;
params.iprop_ulogsize = DEF_ULOGENTRIES;
diff --git a/src/slave/kpropd.c b/src/slave/kpropd.c
index 309717d..b2899bb 100644
--- a/src/slave/kpropd.c
+++ b/src/slave/kpropd.c
@@ -101,17 +101,11 @@ extern int daemon(int, int);
#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
@@ -132,11 +126,16 @@ typedef struct _kadm5_iprop_handle_t {
static char *kprop_version = KPROP_PROT_VERSION;
+static kadm5_config_params params;
+
char *progname;
int debug = 0;
+int nodaemon = 0;
char *srvtab = 0;
int standalone = 0;
+pid_t fullprop_child = (pid_t)-1;
+
krb5_principal server; /* This is our server principal name */
krb5_principal client; /* This is who we're talking to */
krb5_context kpropd_context;
@@ -156,7 +155,7 @@ char **db_args = NULL;
int db_args_size = 0;
void PRS(char**);
-int do_standalone(iprop_role iproprole);
+void do_standalone(void);
void doit(int);
krb5_error_code do_iprop(kdb_log_context *log_ctx);
void kerberos_authenticate(krb5_context, int, krb5_principal *,
@@ -183,59 +182,142 @@ static void usage()
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
+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;
{
krb5_error_code retval;
- int ret = 0;
kdb_log_context *log_ctx;
+ int devnull, sock;
setlocale(LC_ALL, "");
PRS(argv);
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.
+ */
+ 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);
+ 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(log_ctx);
+ /* 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
@@ -257,19 +339,16 @@ get_wildcard_addr(struct addrinfo **res)
return getaddrinfo(NULL, port, &hints, res);
}
-int do_standalone(iprop_role iproprole)
+void
+do_standalone()
{
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 ret, error, val, status;
+ pid_t child_pid;
+ pid_t wait_pid;
error = get_wildcard_addr(&res);
if (error != 0) {
@@ -296,60 +375,15 @@ retry:
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) {
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;
-
memset(&frominet, 0, sizeof(frominet));
fromlen = sizeof(frominet);
if (debug)
@@ -361,30 +395,9 @@ retry:
if (e != EINTR) {
com_err(progname, e,
_("while accepting connection"));
- if (e != EBADF)
- backoff_timer = INITIAL_TIMER;
}
- /*
- * 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"));
@@ -396,31 +409,22 @@ retry:
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) {
com_err(progname, errno,
_("while waiting to receive database"));
- if (iproprole != IPROP_SLAVE)
- exit(1);
- sleep(3);
+ exit(1);
}
close(s);
- if (iproprole == IPROP_SLAVE) {
- close(finet);
- if ((ret = WEXITSTATUS(status)) != 0)
- return (ret);
- }
+
+ if (runonce)
+ break;
}
- if (iproprole == IPROP_SLAVE)
- break;
}
- return 0;
+ exit(0);
}
void doit(fd)
@@ -437,23 +441,8 @@ void doit(fd)
int database_fd;
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);
- }
- }
- }
+ signal_wrapper(SIGALRM, alarm_handler);
+ alarm(params.iprop_resync_timeout);
fromlen = sizeof (from);
if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
#ifdef ENOTSOCK
@@ -488,12 +477,6 @@ void doit(fd)
*/
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;
@@ -601,10 +584,13 @@ full_resync(CLIENT *clnt)
}
/*
- * 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(kdb_log_context *log_ctx)
{
kadm5_ret_t retval;
krb5_ccache cc;
@@ -615,24 +601,21 @@ krb5_error_code do_iprop(kdb_log_context *log_ctx)
unsigned int pollin, backoff_time;
int backoff_cnt = 0;
int reinit_cnt = 0;
- int ret;
- int frdone = 0;
+ time_t frrequested = 0;
+ time_t 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;
pollin = params.iprop_poll_time;
- if (pollin < 10)
+ if (pollin == 0)
pollin = 10;
/*
@@ -643,7 +626,7 @@ krb5_error_code do_iprop(kdb_log_context *log_ctx)
if (retval) {
com_err(progname, retval,
_("Unable to get default realm"));
- exit(1);
+ return retval;
}
}
@@ -658,7 +641,7 @@ krb5_error_code do_iprop(kdb_log_context *log_ctx)
_("%s: unable to get kiprop host based "
"service name for realm %s\n"),
progname, def_realm);
- exit(1);
+ return retval;
}
}
@@ -669,7 +652,7 @@ krb5_error_code do_iprop(kdb_log_context *log_ctx)
com_err(progname, retval,
_("while opening default "
"credentials cache"));
- exit(1);
+ return retval;
}
retval = krb5_sname_to_principal(kpropd_context, NULL, KIPROP_SVC_NAME,
@@ -677,7 +660,7 @@ krb5_error_code do_iprop(kdb_log_context *log_ctx)
if (retval) {
com_err(progname, retval,
_("while trying to construct host service principal"));
- exit(1);
+ return retval;
}
/* XXX referrals? */
@@ -691,7 +674,7 @@ krb5_error_code do_iprop(kdb_log_context *log_ctx)
if (r->data == NULL) {
com_err(progname, retval,
_("while determining local service principal name"));
- exit(1);
+ return retval;
}
/* XXX Memory leak: Old r->data value. */
}
@@ -700,7 +683,7 @@ krb5_error_code do_iprop(kdb_log_context *log_ctx)
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);
@@ -792,14 +775,19 @@ 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) {
break;
} else {
+ frrequested = now;
full_ret = full_resync(handle->clnt);
if (full_ret == (kdb_fullresync_result_t *)
NULL) {
@@ -817,28 +805,6 @@ reinit:
switch (full_ret->ret) {
case UPDATE_OK:
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:
@@ -852,7 +818,6 @@ reinit:
case UPDATE_NIL:
default:
backoff_cnt = 0;
- frdone = 0;
syslog(LOG_ERR, _("kpropd: Full resync,"
" invalid return from master KDC."));
break;
@@ -871,7 +836,7 @@ reinit:
case UPDATE_OK:
backoff_cnt = 0;
- frdone = 0;
+ frrequested = 0;
/*
* ulog_replay() will convert the ulog updates to db
@@ -920,7 +885,7 @@ reinit:
fprintf(stderr, _("Master, slave KDC's "
"are in-sync, no updates\n"));
backoff_cnt = 0;
- frdone = 0;
+ frrequested = 0;
break;
default:
@@ -965,7 +930,7 @@ done:
if ((retval = krb5_cc_close(kpropd_context, cc))) {
com_err(progname, retval,
_("while closing default ccache"));
- exit(1);
+ return retval;
}
if (def_realm && kpropd_context)
krb5_free_default_realm(kpropd_context, def_realm);
@@ -977,7 +942,7 @@ done:
if (runonce == 1)
return (0);
else
- exit(1);
+ return 1;
}
@@ -1096,6 +1061,9 @@ void PRS(argv)
usage();
word = 0;
break;
+ case 'D':
+ nodaemon++;
+ break;
case 'd':
debug++;
break;
@@ -1117,7 +1085,7 @@ void PRS(argv)
* Undocumented option - for testing only.
*
* Option to run the kpropd server exactly
- * once (this is true only if iprop is enabled).
+ * once.
*/
runonce = 1;
break;
@@ -1580,7 +1548,7 @@ load_database(context, kdb_util, database_file_name)
char *database_file_name;
{
static char *edit_av[10];
- int error_ret, save_stderr = -1;
+ int error_ret;
int child_pid;
int count;
@@ -1594,7 +1562,6 @@ load_database(context, kdb_util, database_file_name)
#else
int waitb;
#endif
- krb5_error_code retval;
kdb_log_context *log_ctx;
if (debug)
@@ -1624,23 +1591,8 @@ load_database(context, kdb_util, database_file_name)
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:
More information about the cvs-krb5
mailing list