Imported Upstream version 2.6.1
[debian/amanda] / amandad-src / amandad.c
index 772cd39df3bc5d66d69e15a35441165a0cebe217..cfb7a47948ec7edeb04786fe85e9058f389a468c 100644 (file)
@@ -32,8 +32,6 @@
  * master side
  */
 
-/*#define      AMANDAD_DEBUG*/
-
 #include "amanda.h"
 #include "amandad.h"
 #include "clock.h"
 #include "security.h"
 #include "stream.h"
 #include "util.h"
+#include "conffile.h"
 
 #define        REP_TIMEOUT     (6*60*60)       /* secs for service to reply */
 #define        ACK_TIMEOUT     10              /* XXX should be configurable */
-#define        MAX_REP_RETRIES 5
+#define STDERR_PIPE (DATA_FD_COUNT + 1)
+
+#define amandad_debug(i, ...) do {     \
+       if ((i) <= debug_amandad) {     \
+               dbprintf(__VA_ARGS__);  \
+       }                               \
+} while (0)
 
 /*
  * These are the actions for entering the state machine
@@ -63,6 +68,37 @@ typedef enum { A_START, A_RECVPKT, A_RECVREP, A_PENDING, A_FINISH, A_CONTINUE,
 struct active_service;
 typedef action_t (*state_t)(struct active_service *, action_t, pkt_t *);
 
+/* string that we scan for in sendbackup's MESG stream */
+static const char info_end_str[] = "sendbackup: info end\n";
+#define INFO_END_LEN (sizeof(info_end_str)-1)
+
+/* 
+ * Here are the services that we allow.
+ * Must be in the same order as services[].
+ */
+typedef enum {
+    SERVICE_NOOP,
+    SERVICE_SENDSIZE,
+    SERVICE_SENDBACKUP,
+    SERVICE_SELFCHECK,
+    SERVICE_AMINDEXD,
+    SERVICE_AMIDXTAPED
+} service_t;
+
+static struct services {
+    char *name;
+    int  active;
+    service_t service;
+} services[] = {
+   { "noop", 1, SERVICE_NOOP },
+   { "sendsize", 1, SERVICE_SENDSIZE },
+   { "sendbackup", 1, SERVICE_SENDBACKUP },
+   { "selfcheck", 1, SERVICE_SELFCHECK },
+   { "amindexd", 0, SERVICE_AMINDEXD },
+   { "amidxtaped", 0, SERVICE_AMIDXTAPED }
+};
+#define        NSERVICES       (int)(sizeof(services) / sizeof(services[0]))
+
 /*
  * This structure describes an active running service.
  *
@@ -72,6 +108,7 @@ typedef action_t (*state_t)(struct active_service *, action_t, pkt_t *);
  * for communications with the amanda server.
  */
 struct active_service {
+    service_t service;                 /* service name */
     char *cmd;                         /* name of command we ran */
     char *arguments;                   /* arguments we sent it */
     security_handle_t *security_handle;        /* remote server */
@@ -80,13 +117,19 @@ struct active_service {
     int send_partial_reply;            /* send PREP packet */
     int reqfd;                         /* pipe to write requests */
     int repfd;                         /* pipe to read replies */
+    int errfd;                         /* pipe to read stderr */
     event_handle_t *ev_repfd;          /* read event handle for repfd */
     event_handle_t *ev_reptimeout;     /* timeout for rep data */
+    event_handle_t *ev_errfd;          /* read event handle for errfd */
     pkt_t rep_pkt;                     /* rep packet we're sending out */
+    char *errbuf;                      /* buffer to read the err into */
     char *repbuf;                      /* buffer to read the rep into */
     size_t bufsize;                    /* length of repbuf */
     size_t repbufsize;                 /* length of repbuf */
     int repretry;                      /* times we'll retry sending the rep */
+    int seen_info_end;                 /* have we seen "sendbackup info end\n"? */
+    char info_end_buf[INFO_END_LEN];   /* last few bytes read, used for scanning for info end */
+
     /*
      * General user streams to the process, and their equivalent
      * network streams.
@@ -103,22 +146,6 @@ struct active_service {
     TAILQ_ENTRY(active_service) tq;    /* queue handle */
 };
 
-/* 
- * Here are the services that we allow.
- */
-static struct services {
-    char *name;
-    int  active;
-} services[] = {
-    { "noop", 1 },
-    { "sendsize", 1 },
-    { "sendbackup", 1 },
-    { "selfcheck", 1 },
-    { "amindexd", 0 },
-    { "amidxtaped", 0 }
-};
-#define        NSERVICES       (int)(sizeof(services) / sizeof(services[0]))
-
 /*
  * Queue of outstanding requests that we are running.
  */
@@ -129,20 +156,10 @@ static struct {
     TAILQ_HEAD_INITIALIZER(serviceq.tailq), 0
 };
 
-/*
- * Data for dbmalloc to check for memory leaks
- */
-#ifdef USE_DBMALLOC
-static struct {
-    struct {
-       unsigned long size, hist;
-    } start, end;
-} dbmalloc_info;
-#endif
-
 static int wait_30s = 1;
 static int exit_on_qlength = 1;
 static char *auth = NULL;
+static kencrypt_type amandad_kencrypt = KENCRYPT_NONE;
 
 int main(int argc, char **argv);
 
@@ -158,41 +175,20 @@ static action_t s_sendrep(struct active_service *, action_t, pkt_t *);
 static action_t s_ackwait(struct active_service *, action_t, pkt_t *);
 
 static void repfd_recv(void *);
+static void errfd_recv(void *);
 static void timeout_repfd(void *);
 static void protocol_recv(void *, pkt_t *, security_status_t);
 static void process_readnetfd(void *);
 static void process_writenetfd(void *, void *, ssize_t);
 static struct active_service *service_new(security_handle_t *,
-    const char *, const char *);
+    const char *, service_t, const char *);
 static void service_delete(struct active_service *);
 static int writebuf(struct active_service *, const void *, size_t);
 static ssize_t do_sendpkt(security_handle_t *handle, pkt_t *pkt);
+static char *amandad_get_security_conf (char *, void *);
 
-static void child_signal(int signal);
-
-#ifdef AMANDAD_DEBUG
 static const char *state2str(state_t);
 static const char *action2str(action_t);
-#endif
-
-/*
- * Harvests defunct processes...
- */
-
-static void
-child_signal(
-    int                signal)
-{
-    pid_t      rp;
-
-    (void)signal;      /* Quite compiler warning */
-    /*
-     * Reap and child status and promptly ignore since we don't care...
-     */
-    do {
-       rp = waitpid(-1, NULL, WNOHANG);
-    } while (rp > 0);
-}
 
 int
 main(
@@ -204,13 +200,21 @@ main(
     int in, out;
     const security_driver_t *secdrv;
     int no_exit = 0;
-    struct sigaction act, oact;
     char *pgm = "amandad";             /* in case argv[0] is not set */
-#if defined(AMANDAD_DEBUG) && defined(USE_REUSEADDR)
+#if defined(USE_REUSEADDR)
     const int on = 1;
     int r;
 #endif
 
+    /*
+     * Configure program for internationalization:
+     *   1) Only set the message locale for now.
+     *   2) Set textdomain for all amanda related programs to "amanda"
+     *      We don't want to be forced to support dozens of message catalogs.
+     */  
+    setlocale(LC_MESSAGES, "C");
+    textdomain("amanda"); 
+
     safe_fd(-1, 0);
     safe_cd();
 
@@ -229,51 +233,35 @@ main(
     dbopen(DBG_SUBDIR_AMANDAD);
 
     if(argv == NULL) {
-       error("argv == NULL\n");
+       error(_("argv == NULL\n"));
        /*NOTREACHED*/
     }
 
     /* Don't die when child closes pipe */
     signal(SIGPIPE, SIG_IGN);
 
-    /* Tell me when a child exits or dies... */
-    act.sa_handler = child_signal;
-    sigemptyset(&act.sa_mask);
-    act.sa_flags = 0;
-    if(sigaction(SIGCHLD, &act, &oact) != 0) {
-       error("error setting SIGCHLD handler: %s", strerror(errno));
-       /*NOTREACHED*/
-    }
-
-#ifdef USE_DBMALLOC
-    dbmalloc_info.start.size = malloc_inuse(&dbmalloc_info.start.hist);
-#endif
-
-    erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
+    /* Parse the configuration; we'll handle errors later */
+    config_init(CONFIG_INIT_CLIENT, NULL);
 
-#ifdef FORCE_USERID
-    /* we'd rather not run as root */
     if (geteuid() == 0) {
-       if(client_uid == (uid_t) -1) {
-           error("error [cannot find user %s in passwd file]\n", CLIENT_LOGIN);
-           /*NOTREACHED*/
-       }
-       initgroups(CLIENT_LOGIN, client_gid);
-       setgid(client_gid);
-       setegid(client_gid);
-       seteuid(client_uid);
+       check_running_as(RUNNING_AS_ROOT);
+       initgroups(CLIENT_LOGIN, get_client_gid());
+       setgid(get_client_gid());
+       setegid(get_client_gid());
+       seteuid(get_client_uid());
+    } else {
+       check_running_as(RUNNING_AS_CLIENT_LOGIN);
     }
-#endif /* FORCE_USERID */
+
+    erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
 
     /*
      * ad-hoc argument parsing
      *
      * We accept       -auth=[authentication type]
      *                 -no-exit
-#ifdef AMANDAD_DEBUG
      *                 -tcp=[port]
      *                 -udp=[port]
-#endif
      * We also add a list of services that amandad can launch
      */
     secdrv = NULL;
@@ -297,7 +285,7 @@ main(
            secdrv = security_getdriver(argv[i]);
            auth = argv[i];
            if (secdrv == NULL) {
-               error("no driver for security type '%s'\n", argv[i]);
+               error(_("no driver for security type '%s'\n"), argv[i]);
                 /*NOTREACHED*/
            }
            continue;
@@ -312,35 +300,47 @@ main(
            continue;
        }
 
-#ifdef AMANDAD_DEBUG
        /*
         * Allow us to directly bind to a udp port for debugging.
         * This may only apply to some security types.
         */
        else if (strncmp(argv[i], "-udp=", strlen("-udp=")) == 0) {
+#ifdef WORKING_IPV6
+           struct sockaddr_in6 sin;
+#else
            struct sockaddr_in sin;
+#endif
 
            argv[i] += strlen("-udp=");
+#ifdef WORKING_IPV6
+           in = out = socket(AF_INET6, SOCK_DGRAM, 0);
+#else
            in = out = socket(AF_INET, SOCK_DGRAM, 0);
+#endif
            if (in < 0) {
-               error("can't create dgram socket: %s\n", strerror(errno));
+               error(_("can't create dgram socket: %s\n"), strerror(errno));
                /*NOTREACHED*/
            }
 #ifdef USE_REUSEADDR
            r = setsockopt(in, SOL_SOCKET, SO_REUSEADDR,
-               (void *)&on, (socklen_t)sizeof(on));
+               (void *)&on, (socklen_t_equiv)sizeof(on));
            if (r < 0) {
-               dbprintf(("%s: amandad: setsockopt(SO_REUSEADDR) failed: %s\n",
-                         debug_prefix(NULL),
-                         strerror(errno)));
+               dbprintf(_("amandad: setsockopt(SO_REUSEADDR) failed: %s\n"),
+                         strerror(errno));
            }
 #endif
 
+#ifdef WORKING_IPV6
+           sin.sin6_family = (sa_family_t)AF_INET6;
+           sin.sin6_addr = in6addr_any;
+           sin.sin6_port = (in_port_t)htons((in_port_t)atoi(argv[i]));
+#else
            sin.sin_family = (sa_family_t)AF_INET;
            sin.sin_addr.s_addr = INADDR_ANY;
            sin.sin_port = (in_port_t)htons((in_port_t)atoi(argv[i]));
-           if (bind(in, (struct sockaddr *)&sin, (socklen_t)sizeof(sin)) < 0) {
-               error("can't bind to port %d: %s\n", atoi(argv[i]),
+#endif
+           if (bind(in, (struct sockaddr *)&sin, (socklen_t_equiv)sizeof(sin)) < 0) {
+               error(_("can't bind to port %d: %s\n"), atoi(argv[i]),
                    strerror(errno));
                /*NOTREACHED*/
            }
@@ -349,41 +349,50 @@ main(
         * Ditto for tcp ports.
         */
        else if (strncmp(argv[i], "-tcp=", strlen("-tcp=")) == 0) {
+#ifdef WORKING_IPV6
+           struct sockaddr_in6 sin;
+#else
            struct sockaddr_in sin;
+#endif
            int sock;
-           socklen_t n;
+           socklen_t_equiv n;
 
            argv[i] += strlen("-tcp=");
+#ifdef WORKING_IPV6
+           sock = socket(AF_INET6, SOCK_STREAM, 0);
+#else
            sock = socket(AF_INET, SOCK_STREAM, 0);
+#endif
            if (sock < 0) {
-               error("can't create tcp socket: %s\n", strerror(errno));
+               error(_("can't create tcp socket: %s\n"), strerror(errno));
                /*NOTREACHED*/
            }
-           n = 1;
 #ifdef USE_REUSEADDR
            r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-               (void *)&on, (socklen_t)sizeof(on));
+               (void *)&on, (socklen_t_equiv)sizeof(on));
            if (r < 0) {
-               dbprintf(("%s: amandad: setsockopt(SO_REUSEADDR) failed: %s\n",
-                         debug_prefix(NULL),
-                         strerror(errno)));
+               dbprintf(_("amandad: setsockopt(SO_REUSEADDR) failed: %s\n"),
+                         strerror(errno));
            }
 #endif
-           setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-               (void *)&n, (socklen_t)sizeof(n));
+#ifdef WORKING_IPV6
+           sin.sin6_family = (sa_family_t)AF_INET6;
+           sin.sin6_addr = in6addr_any;
+           sin.sin6_port = (in_port_t)htons((in_port_t)atoi(argv[i]));
+#else
            sin.sin_family = (sa_family_t)AF_INET;
            sin.sin_addr.s_addr = INADDR_ANY;
            sin.sin_port = (in_port_t)htons((in_port_t)atoi(argv[i]));
-           if (bind(sock, (struct sockaddr *)&sin, (socklen_t)sizeof(sin)) < 0) {
-               error("can't bind to port %d: %s\n", atoi(argv[i]),
+#endif
+           if (bind(sock, (struct sockaddr *)&sin, (socklen_t_equiv)sizeof(sin)) < 0) {
+               error(_("can't bind to port %d: %s\n"), atoi(argv[i]),
                    strerror(errno));
                /*NOTREACHED*/
            }
            listen(sock, 10);
-           n = (socklen_t)sizeof(sin);
+           n = (socklen_t_equiv)sizeof(sin);
            in = out = accept(sock, (struct sockaddr *)&sin, &n);
        }
-#endif
        /*
         * It must be a service name
         */
@@ -406,8 +415,7 @@ main(
                    if (strcmp(services[j].name, argv[i]) == 0)
                        break;
                if (j == (int)NSERVICES) {
-                   dbprintf(("%s: %s: invalid service\n",
-                             debug_prefix_time(NULL), argv[i]));
+                   dbprintf(_("%s: invalid service\n"), argv[i]);
                    exit(1);
                }
                services[j].active = 1;
@@ -422,37 +430,54 @@ main(
        secdrv = security_getdriver("BSD");
        auth = "bsd";
        if (secdrv == NULL) {
-           error("no driver for default security type 'BSD'\n");
+           error(_("no driver for default security type 'BSD'\n"));
            /*NOTREACHED*/
        }
     }
 
     if(strcasecmp(auth, "rsh") == 0 ||
        strcasecmp(auth, "ssh") == 0 ||
+       strcasecmp(auth, "local") == 0 ||
        strcasecmp(auth, "bsdtcp") == 0) {
        wait_30s = 0;
        exit_on_qlength = 1;
     }
 
+    if (getuid() == 0) {
+       if (strcasecmp(auth, "krb5") != 0) {
+           error(_("Amanda must be run as user '%s' when using '%s' authentication"),
+                 CLIENT_LOGIN, auth);
+       }
+    } else {
+       if (strcasecmp(auth, "krb5") == 0) {
+           error(_("Amanda must be run as user 'root' when using 'krb5' authentication"));
+       }
+    }
+
+
     /* initialize */
 
     startclock();
 
-    dbprintf(("%s: version %s\n", get_pname(), version()));
+    dbprintf(_("version %s\n"), version());
     for (i = 0; version_info[i] != NULL; i++) {
-       dbprintf(("%s: %s", debug_prefix(NULL), version_info[i]));
+       dbprintf("    %s", version_info[i]);
     }
 
     if (! (argc >= 1 && argv != NULL && argv[0] != NULL)) {
-       dbprintf(("%s: WARNING: argv[0] not defined: check inetd.conf\n",
-                 debug_prefix(NULL)));
+       dbprintf(_("WARNING: argv[0] not defined: check inetd.conf\n"));
+    }
+
+    /* krb5 require the euid to be 0 */
+    if (strcasecmp(auth, "krb5") == 0) {
+       seteuid((uid_t)0);
     }
 
     /*
      * Schedule to call protocol_accept() when new security handles
      * are created on stdin.
      */
-    security_accept(secdrv, in, out, protocol_accept);
+    security_accept(secdrv, amandad_get_security_conf, in, out, protocol_accept, NULL);
 
     /*
      * Schedule an event that will try to exit every 30 seconds if there
@@ -498,15 +523,6 @@ exit_check(
     if (no_exit)
        return;
 
-#ifdef USE_DBMALLOC
-    dbmalloc_info.end.size = malloc_inuse(&dbmalloc_info.end.hist);
-
-    if (dbmalloc_info.start.size != dbmalloc_info.end.size) {
-       malloc_list(dbfd(), dbmalloc_info.start.hist,
-           dbmalloc_info.end.hist);
-    }
-#endif
-
     dbclose();
     exit(0);
 }
@@ -524,6 +540,7 @@ protocol_accept(
     struct active_service *as;
     char *pktbody, *tok, *service, *arguments;
     char *service_path = NULL;
+    GSList *errlist = NULL;
     int i;
 
     pkt_out.body = NULL;
@@ -535,12 +552,37 @@ protocol_accept(
        return;
     }
 
+    /*
+     * If we have errors (not warnings) from the config file, let the server
+     * know immediately.  Unfortunately, we only get one ERROR line, so if there
+     * are multiple errors, we just show the first.
+     */
+    if (config_errors(&errlist) >= CFGERR_ERRORS) {
+       GSList *iter = errlist;
+       char *errmsg;
+       gboolean multiple_errors = FALSE;
+
+       if (iter) {
+           errmsg = (char *)iter->data;
+           if (iter->next)
+               multiple_errors = TRUE;
+       } else {
+           errmsg = "(no error message)";
+       }
+
+       pkt_init(&pkt_out, P_NAK, "ERROR %s%s", errmsg,
+           multiple_errors? _(" (additional errors not displayed)"):"");
+       do_sendpkt(handle, &pkt_out);
+       amfree(pkt_out.body);
+       security_close(handle);
+       return;
+    }
+
     /*
      * If pkt is NULL, then there was a problem with the new connection.
      */
     if (pkt == NULL) {
-       dbprintf(("%s: accept error: %s\n",
-           debug_prefix_time(NULL), security_geterror(handle)));
+       dbprintf(_("accept error: %s\n"), security_geterror(handle));
        pkt_init(&pkt_out, P_NAK, "ERROR %s\n", security_geterror(handle));
        do_sendpkt(handle, &pkt_out);
        amfree(pkt_out.body);
@@ -548,15 +590,15 @@ protocol_accept(
        return;
     }
 
-    dbprintf(("%s: accept recv %s pkt:\n<<<<<\n%s>>>>>\n",
-       debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->body));
+    dbprintf(_("accept recv %s pkt:\n<<<<<\n%s>>>>>\n"),
+       pkt_type2str(pkt->type), pkt->body);
 
     /*
      * If this is not a REQ packet, just forget about it.
      */
     if (pkt->type != P_REQ) {
-       dbprintf(("%s: received unexpected %s packet:\n<<<<<\n%s>>>>>\n\n",
-           debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->body));
+       dbprintf(_("received unexpected %s packet:\n<<<<<\n%s>>>>>\n\n"),
+           pkt_type2str(pkt->type), pkt->body);
        security_close(handle);
        return;
     }
@@ -592,18 +634,16 @@ protocol_accept(
        if (services[i].active == 1 && strcmp(services[i].name, service) == 0)
            break;
     if (i == (int)NSERVICES) {
-       dbprintf(("%s: %s: invalid service\n",
-           debug_prefix_time(NULL), service));
-       pkt_init(&pkt_out, P_NAK, "ERROR %s: invalid service\n", service);
+       dbprintf(_("%s: invalid service\n"), service);
+       pkt_init(&pkt_out, P_NAK, _("ERROR %s: invalid service, add '%s' as argument to amandad\n"), service, service);
        goto send_pkt_out;
     }
 
-    service_path = vstralloc(libexecdir, "/", service, versionsuffix(), NULL);
+    service_path = vstralloc(amlibexecdir, "/", service, versionsuffix(), NULL);
     if (access(service_path, X_OK) < 0) {
-       dbprintf(("%s: can't execute %s: %s\n",
-           debug_prefix_time(NULL), service_path, strerror(errno)));
+       dbprintf(_("can't execute %s: %s\n"), service_path, strerror(errno));
            pkt_init(&pkt_out, P_NAK,
-                    "ERROR execute access to \"%s\" denied\n",
+                    _("ERROR execute access to \"%s\" denied\n"),
                     service_path);
        goto send_pkt_out;
     }
@@ -613,9 +653,9 @@ protocol_accept(
        as = TAILQ_NEXT(as, tq)) {
            if (strcmp(as->cmd, service_path) == 0 &&
                strcmp(as->arguments, arguments) == 0) {
-                   dbprintf(("%s: %s %s: already running, acking req\n",
-                       debug_prefix_time(NULL), service, arguments));
-                   pkt_init(&pkt_out, P_ACK, "");
+                   dbprintf(_("%s %s: already running, acking req\n"),
+                       service, arguments);
+                   pkt_init_empty(&pkt_out, P_ACK);
                    goto send_pkt_out_no_delete;
            }
     }
@@ -624,14 +664,12 @@ protocol_accept(
      * create a new service instance, and send the arguments down
      * the request pipe.
      */
-    dbprintf(("%s: creating new service: %s\n%s\n",
-       debug_prefix_time(NULL), service, arguments));
-    as = service_new(handle, service_path, arguments);
+    dbprintf(_("creating new service: %s\n%s\n"), service, arguments);
+    as = service_new(handle, service_path, services[i].service, arguments);
     if (writebuf(as, arguments, strlen(arguments)) < 0) {
        const char *errmsg = strerror(errno);
-       dbprintf(("%s: error sending arguments to %s: %s\n",
-           debug_prefix_time(NULL), service, errmsg));
-       pkt_init(&pkt_out, P_NAK, "ERROR error writing arguments to %s: %s\n",
+       dbprintf(_("error sending arguments to %s: %s\n"), service, errmsg);
+       pkt_init(&pkt_out, P_NAK, _("ERROR error writing arguments to %s: %s\n"),
            service, errmsg);
        goto send_pkt_out;
     }
@@ -651,9 +689,9 @@ protocol_accept(
     return;
 
 badreq:
-    pkt_init(&pkt_out, P_NAK, "ERROR invalid REQ\n");
-    dbprintf(("%s: received invalid %s packet:\n<<<<<\n%s>>>>>\n\n",
-       debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->body));
+    pkt_init(&pkt_out, P_NAK, _("ERROR invalid REQ\n"));
+    dbprintf(_("received invalid %s packet:\n<<<<<\n%s>>>>>\n\n"),
+       pkt_type2str(pkt->type), pkt->body);
 
 send_pkt_out:
     if(as)
@@ -682,34 +720,22 @@ state_machine(
     state_t curstate;
     pkt_t nak;
 
-#ifdef AMANDAD_DEBUG
-    dbprintf(("%s: state_machine: %p entering\n",
-       debug_prefix_time(NULL), as));
-#endif
+    amandad_debug(1, _("state_machine: %p entering\n"), as);
     for (;;) {
        curstate = as->state;
-#ifdef AMANDAD_DEBUG
-       dbprintf(("%s: state_machine: %p curstate=%s action=%s\n",
-           debug_prefix_time(NULL), as,
-           state2str(curstate), action2str(action)));
-#endif
+       amandad_debug(1, _("state_machine: %p curstate=%s action=%s\n"), as,
+                         state2str(curstate), action2str(action));
        retaction = (*curstate)(as, action, pkt);
-#ifdef AMANDAD_DEBUG
-       dbprintf(("%s: state_machine: %p curstate=%s returned %s (nextstate=%s)\n",
-           debug_prefix_time(NULL),
-           as, state2str(curstate), action2str(retaction),
-           state2str(as->state)));
-#endif
+       amandad_debug(1, _("state_machine: %p curstate=%s returned %s (nextstate=%s)\n"),
+                         as, state2str(curstate), action2str(retaction),
+                         state2str(as->state));
 
        switch (retaction) {
        /*
         * State has queued up and is now blocking on input.
         */
        case A_PENDING:
-#ifdef AMANDAD_DEBUG
-           dbprintf(("%s: state_machine: %p leaving (A_PENDING)\n",
-               debug_prefix_time(NULL), as));
-#endif
+           amandad_debug(1, _("state_machine: %p leaving (A_PENDING)\n"), as);
            return;
 
        /*
@@ -723,28 +749,23 @@ state_machine(
         * Send a nak, and return.
         */
        case A_SENDNAK:
-           dbprintf(("%s: received unexpected %s packet\n",
-               debug_prefix_time(NULL), pkt_type2str(pkt->type)));
-           dbprintf(("<<<<<\n%s----\n\n", pkt->body));
-           pkt_init(&nak, P_NAK, "ERROR unexpected packet type %s\n",
+           dbprintf(_("received unexpected %s packet\n"),
+               pkt_type2str(pkt->type));
+           dbprintf(_("<<<<<\n%s----\n\n"), pkt->body);
+           pkt_init(&nak, P_NAK, _("ERROR unexpected packet type %s\n"),
                pkt_type2str(pkt->type));
            do_sendpkt(as->security_handle, &nak);
            amfree(nak.body);
-#ifdef AMANDAD_DEBUG
-           dbprintf(("%s: state_machine: %p leaving (A_SENDNAK)\n",
-               debug_prefix_time(NULL), as));
-#endif
+           security_recvpkt(as->security_handle, protocol_recv, as, -1);
+           amandad_debug(1, _("state_machine: %p leaving (A_SENDNAK)\n"), as);
            return;
 
        /*
         * Service is done.  Remove it and finish.
         */
        case A_FINISH:
+           amandad_debug(1, _("state_machine: %p leaving (A_FINISH)\n"), as);
            service_delete(as);
-#ifdef AMANDAD_DEBUG
-           dbprintf(("%s: state_machine: %p leaving (A_FINISH)\n",
-               debug_prefix_time(NULL), as));
-#endif
            return;
 
        default:
@@ -770,10 +791,10 @@ s_sendack(
     (void)action;      /* Quiet unused parameter warning */
     (void)pkt;         /* Quiet unused parameter warning */
 
-    pkt_init(&ack, P_ACK, "");
+    pkt_init_empty(&ack, P_ACK);
     if (do_sendpkt(as->security_handle, &ack) < 0) {
-       dbprintf(("%s: error sending ACK: %s\n",
-           debug_prefix_time(NULL), security_geterror(as->security_handle)));
+       dbprintf(_("error sending ACK: %s\n"),
+           security_geterror(as->security_handle));
        amfree(ack.body);
        return (A_FINISH);
     }
@@ -791,6 +812,8 @@ s_sendack(
     as->ev_repfd = event_register((event_id_t)as->repfd, EV_READFD, repfd_recv, as);
     as->ev_reptimeout = event_register(REP_TIMEOUT, EV_TIME,
        timeout_repfd, as);
+    as->errbuf = NULL;
+    as->ev_errfd = event_register((event_id_t)as->errfd, EV_READFD, errfd_recv, as);
     security_recvpkt(as->security_handle, protocol_recv, as, -1);
     return (A_PENDING);
 }
@@ -806,8 +829,13 @@ s_repwait(
     action_t                   action,
     pkt_t *                    pkt)
 {
-    ssize_t n;
-    char *repbuf_temp;
+    ssize_t   n;
+    char     *repbuf_temp;
+    char     *what;
+    char     *msg;
+    int       code = 0;
+    int       pid;
+    amwait_t  retstat;
 
     /*
      * We normally shouldn't receive any packets while waiting
@@ -820,11 +848,11 @@ s_repwait(
         * and go back and wait for more data.
         */
        if (pkt->type == P_REQ) {
-           dbprintf(("%s: received dup P_REQ packet, ACKing it\n",
-               debug_prefix_time(NULL)));
+           dbprintf(_("received dup P_REQ packet, ACKing it\n"));
            amfree(as->rep_pkt.body);
-           pkt_init(&as->rep_pkt, P_ACK, "");
+           pkt_init_empty(&as->rep_pkt, P_ACK);
            do_sendpkt(as->security_handle, &as->rep_pkt);
+           security_recvpkt(as->security_handle, protocol_recv, as, -1);
            return (A_PENDING);
        }
        /* something unexpected.  Nak it */
@@ -833,9 +861,8 @@ s_repwait(
 
     if (action == A_TIMEOUT) {
        amfree(as->rep_pkt.body);
-       pkt_init(&as->rep_pkt, P_NAK, "ERROR timeout on reply pipe\n");
-       dbprintf(("%s: %s timed out waiting for REP data\n",
-           debug_prefix_time(NULL), as->cmd));
+       pkt_init(&as->rep_pkt, P_NAK, _("ERROR timeout on reply pipe\n"));
+       dbprintf(_("%s timed out waiting for REP data\n"), as->cmd);
        do_sendpkt(as->security_handle, &as->rep_pkt);
        return (A_FINISH);
     }
@@ -852,14 +879,78 @@ s_repwait(
     } while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
     if (n < 0) {
        const char *errstr = strerror(errno);
-       dbprintf(("%s: read error on reply pipe: %s\n",
-                 debug_prefix_time(NULL), errstr));
+       dbprintf(_("read error on reply pipe: %s\n"), errstr);
        amfree(as->rep_pkt.body);
-       pkt_init(&as->rep_pkt, P_NAK, "ERROR read error on reply pipe: %s\n",
+       pkt_init(&as->rep_pkt, P_NAK, _("ERROR read error on reply pipe: %s\n"),
                 errstr);
        do_sendpkt(as->security_handle, &as->rep_pkt);
        return (A_FINISH);
     }
+
+    /* If end of service, wait for process status */
+    if (n == 0) {
+       pid = waitpid(as->pid, &retstat, WNOHANG);
+       if (as->service  == SERVICE_NOOP ||
+           as->service  == SERVICE_SENDSIZE ||
+           as->service  == SERVICE_SELFCHECK) {
+           int t = 0;
+           while (t<5 && pid == 0) {
+               sleep(1);
+               t++;
+               pid = waitpid(as->pid, &retstat, WNOHANG);
+           }
+       }
+
+       /* Process errfd before sending the REP packet */
+       if (as->ev_errfd) {
+           SELECT_ARG_TYPE readset;
+           struct timeval  tv;
+           int             nfound;
+
+           memset(&tv, 0, SIZEOF(tv));
+           FD_ZERO(&readset);
+           FD_SET(as->errfd, &readset);
+           nfound = select(as->errfd+1, &readset, NULL, NULL, &tv);
+           if (nfound && FD_ISSET(as->errfd, &readset)) {
+               errfd_recv(as);
+           }
+       }
+
+       if (pid == 0)
+           pid = waitpid(as->pid, &retstat, WNOHANG);
+
+       if (pid > 0) {
+           what = NULL;
+           if (! WIFEXITED(retstat)) {
+               what = _("signal");
+               code = WTERMSIG(retstat);
+           } else if (WEXITSTATUS(retstat) != 0) {
+               what = _("code");
+               code = WEXITSTATUS(retstat);
+           }
+           if (what) {
+               dbprintf(_("service %s failed: pid %u exited with %s %d\n"),
+                        (as->cmd)?as->cmd:_("??UNKONWN??"),
+                        (unsigned)as->pid,
+                        what, code);
+               msg = vstrallocf(
+                    _("ERROR service %s failed: pid %u exited with %s %d\n"),
+                    (as->cmd)?as->cmd:_("??UNKONWN??"), (unsigned)as->pid,
+                    what, code);
+               if (as->repbufsize + strlen(msg) >= (as->bufsize - 1)) {
+                       as->bufsize *= 2;
+                       repbuf_temp = alloc(as->bufsize);
+                       memcpy(repbuf_temp, as->repbuf, as->repbufsize + 1);
+                       amfree(as->repbuf);
+                       as->repbuf = repbuf_temp;
+               }
+               strcpy(as->repbuf + as->repbufsize, msg);
+               as->repbufsize += strlen(msg);
+                amfree(msg);
+           }
+       }
+    }
+
     /*
      * If we got some data, go back and wait for more, or EOF.  Nul terminate
      * the buffer first.
@@ -879,7 +970,7 @@ s_repwait(
            pkt_init(&as->rep_pkt, P_PREP, "%s", as->repbuf);
            do_sendpkt(as->security_handle, &as->rep_pkt);
            amfree(as->rep_pkt.body);
-           pkt_init(&as->rep_pkt, P_REP, "");
+           pkt_init_empty(&as->rep_pkt, P_REP);
        }
  
        return (A_PENDING);
@@ -932,9 +1023,14 @@ s_processrep(
      * We need to map these to security streams and pass them back
      * to the amanda server.  If the handle is -1, then we don't map.
      */
-    repbuf = stralloc(as->repbuf);
+    if (strncmp_const(as->repbuf,"KENCRYPT\n") == 0) {
+        amandad_kencrypt = KENCRYPT_WILL_DO;
+       repbuf = stralloc(as->repbuf + 9);
+    } else {
+       repbuf = stralloc(as->repbuf);
+    }
     amfree(as->rep_pkt.body);
-    pkt_init(&as->rep_pkt, P_REP, "");
+    pkt_init_empty(&as->rep_pkt, P_REP);
     tok = strtok(repbuf, " ");
     if (tok == NULL)
        goto error;
@@ -978,7 +1074,7 @@ error:
      * state.
      */
     as->state = s_sendrep;
-    as->repretry = MAX_REP_RETRIES;
+    as->repretry = getconf_int(CNF_REP_TRIES);
     amfree(repbuf);
     return (A_CONTINUE);
 }
@@ -1025,20 +1121,15 @@ s_ackwait(
            as->state = s_sendrep;
            return (A_CONTINUE);
        }
-       dbprintf(("%s: timeout waiting for ACK for our REP\n",
-           debug_prefix_time(NULL)));
+       dbprintf(_("timeout waiting for ACK for our REP\n"));
        return (A_FINISH);
     }
-#ifdef AMANDAD_DEBUG
-    dbprintf(("%s: received ACK, now opening streams\n",
-       debug_prefix_time(NULL)));
-#endif
+    amandad_debug(1, _("received ACK, now opening streams\n"));
 
     assert(action == A_RECVPKT);
 
     if (pkt->type == P_REQ) {
-       dbprintf(("%s: received dup P_REQ packet, resending REP\n",
-                 debug_prefix_time(NULL)));
+       dbprintf(_("received dup P_REQ packet, resending REP\n"));
        as->state = s_sendrep;
        return (A_CONTINUE);
     }
@@ -1046,6 +1137,10 @@ s_ackwait(
     if (pkt->type != P_ACK)
        return (A_SENDNAK);
 
+    if (amandad_kencrypt == KENCRYPT_WILL_DO) {
+       amandad_kencrypt = KENCRYPT_YES;
+    }
+
     /*
      * Got the ack, now open the pipes
      */
@@ -1053,15 +1148,24 @@ s_ackwait(
        if (dh->netfd == NULL)
            continue;
        if (security_stream_accept(dh->netfd) < 0) {
-           dbprintf(("%s: stream %d accept failed: %s\n",
-               debug_prefix_time(NULL),
-               dh - &as->data[0], security_geterror(as->security_handle)));
+           dbprintf(_("stream %td accept failed: %s\n"),
+               dh - &as->data[0], security_geterror(as->security_handle));
            security_stream_close(dh->netfd);
            dh->netfd = NULL;
+           continue;
+       }
+
+       /* setup an event for reads from it.  As a special case, don't start
+        * listening on as->data[0] until we read some data on another fd, if
+        * the service is sendbackup.  This ensures that we send a MESG or 
+        * INDEX token before any DATA tokens, as dumper assumes. This is a
+        * hack, if that wasn't already obvious! */
+       if (dh != &as->data[0] || as->service != SERVICE_SENDBACKUP) {
+           dh->ev_read = event_register((event_id_t)dh->fd_read, EV_READFD,
+                                        process_readnetfd, dh);
+       } else {
+           amandad_debug(1, "Skipping registration of sendbackup's data FD\n");
        }
-       /* setup an event for reads from it */
-       dh->ev_read = event_register((event_id_t)dh->fd_read, EV_READFD,
-                                    process_readnetfd, dh);
 
        security_stream_read(dh->netfd, process_writenetfd, dh);
 
@@ -1089,10 +1193,7 @@ s_ackwait(
      * If no pipes are open, then we're done.  Otherwise, just start running.
      * The event handlers on all of the pipes will take it from here.
      */
-#ifdef AMANDAD_DEBUG
-    dbprintf(("%s: at end of s_ackwait, npipes is %d\n",
-       debug_prefix_time(NULL), npipes));
-#endif
+    amandad_debug(1, _("at end of s_ackwait, npipes is %d\n"), npipes);
     if (npipes == 0)
        return (A_FINISH);
     else {
@@ -1117,6 +1218,79 @@ repfd_recv(
     state_machine(as, A_RECVREP, NULL);
 }
 
+/*
+ * Called when a errfd has received data
+ */
+static void
+errfd_recv(
+    void *     cookie)
+{
+    struct active_service *as = cookie;
+    char  buf[32769];
+    int   n;
+    char *r;
+
+    assert(as != NULL);
+    assert(as->ev_errfd != NULL);
+
+    n = read(as->errfd, &buf, 32768);
+    /* merge buffer */
+    if (n > 0) {
+       /* Terminate it with '\0' */
+       buf[n+1] = '\0';
+
+       if (as->errbuf) {
+           as->errbuf = vstrextend(&as->errbuf, buf, NULL);
+       } else {
+           as->errbuf = stralloc(buf);
+       }
+    } else if (n == 0) {
+       event_release(as->ev_errfd);
+       as->ev_errfd = NULL;
+    } else { /* n < 0 */
+       event_release(as->ev_errfd);
+       as->ev_errfd = NULL;
+       g_snprintf(buf, 32768,
+                  "error reading stderr or service: %s\n", strerror(errno));
+    }
+
+    /* for each line terminate by '\n' */
+    while (as->errbuf != NULL  && (r = index(as->errbuf, '\n')) != NULL) {
+       char *s;
+
+       *r = '\0';
+       s = vstrallocf("ERROR service %s: %s\n",
+                      services[as->service].name, as->errbuf);
+
+       /* Add to repbuf, error message will be in the REP packet if it
+        * is not already sent
+        */
+       n = strlen(s);
+       if (as->bufsize == 0) {
+           as->bufsize = NETWORK_BLOCK_BYTES;
+           as->repbuf = alloc(as->bufsize);
+       }
+       while (as->bufsize < as->repbufsize + n) {
+           char *repbuf_temp;
+           as->bufsize *= 2;
+           repbuf_temp = alloc(as->bufsize);
+           memcpy(repbuf_temp, as->repbuf, as->repbufsize + 1);
+           amfree(as->repbuf);
+           as->repbuf = repbuf_temp;
+       }
+       memcpy(as->repbuf + as->repbufsize, s, n);
+       as->repbufsize += n;
+
+       dbprintf("%s", s);
+
+       /* remove first line from buffer */
+       r++;
+       s = stralloc(r);
+       amfree(as->errbuf);
+       as->errbuf = s;
+    }
+}
+
 /*
  * Called when a repfd has timed out
  */
@@ -1147,17 +1321,17 @@ protocol_recv(
 
     switch (status) {
     case S_OK:
-       dbprintf(("%s: received %s pkt:\n<<<<<\n%s>>>>>\n",
-           debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->body));
+       dbprintf(_("received %s pkt:\n<<<<<\n%s>>>>>\n"),
+           pkt_type2str(pkt->type), pkt->body);
        state_machine(as, A_RECVPKT, pkt);
        break;
     case S_TIMEOUT:
-       dbprintf(("%s: timeout\n", debug_prefix_time(NULL)));
+       dbprintf(_("timeout\n"));
        state_machine(as, A_TIMEOUT, NULL);
        break;
     case S_ERROR:
-       dbprintf(("%s: receive error: %s\n",
-           debug_prefix_time(NULL), security_geterror(as->security_handle)));
+       dbprintf(_("receive error: %s\n"),
+           security_geterror(as->security_handle));
        break;
     }
 }
@@ -1185,7 +1359,7 @@ process_readnetfd(
      * Process has died.
      */
     if (n < 0) {
-       pkt_init(&nak, P_NAK, "A ERROR data descriptor %d broken: %s\n",
+       pkt_init(&nak, P_NAK, _("A ERROR data descriptor %d broken: %s\n"),
            dh->fd_read, strerror(errno));
        goto sendnak;
     }
@@ -1207,9 +1381,37 @@ process_readnetfd(
        service_delete(as);
        return;
     }
+
+    /* Handle the special case of recognizing "sendbackup info end"
+     * from sendbackup's MESG fd */
+    if (as->service == SERVICE_SENDBACKUP && !as->seen_info_end && dh == &as->data[1]) {
+       /* make a buffer containing the combined data from info_end_buf
+        * and what we've read this time, and search it for info_end_strj
+        * This includes a NULL byte for strstr's sanity. */
+       char *combined_buf = malloc(INFO_END_LEN + n + 1);
+       memcpy(combined_buf, as->info_end_buf, INFO_END_LEN);
+       memcpy(combined_buf+INFO_END_LEN, as->databuf, n);
+       combined_buf[INFO_END_LEN+n] = '\0';
+
+       as->seen_info_end = (strstr(combined_buf, info_end_str) != NULL);
+
+       /* fill info_end_buf from the tail end of combined_buf */
+       memcpy(as->info_end_buf, combined_buf + n, INFO_END_LEN);
+
+       /* if we did see info_end_str, start reading the data fd (fd 0) */
+       if (as->seen_info_end) {
+           struct datafd_handle *dh = &as->data[0];
+           amandad_debug(1, "Opening datafd to sendbackup (delayed until sendbackup sent header info)\n");
+           dh->ev_read = event_register((event_id_t)dh->fd_read, EV_READFD,
+                                        process_readnetfd, dh);
+       } else {
+           amandad_debug(1, "sendbackup header info still not complete\n");
+       }
+    }
+
     if (security_stream_write(dh->netfd, as->databuf, (size_t)n) < 0) {
        /* stream has croaked */
-       pkt_init(&nak, P_NAK, "ERROR write error on stream %d: %s\n",
+       pkt_init(&nak, P_NAK, _("ERROR write error on stream %d: %s\n"),
            security_stream_id(dh->netfd),
            security_stream_geterror(dh->netfd));
        goto sendnak;
@@ -1238,10 +1440,9 @@ process_writenetfd(
     dh = cookie;
 
     if (dh->fd_write <= 0) {
-       dbprintf(("%s: process_writenetfd: dh->fd_write <= 0\n",
-           debug_prefix_time(NULL)));
+       dbprintf(_("process_writenetfd: dh->fd_write <= 0\n"));
     } else if (size > 0) {
-       fullwrite(dh->fd_write, buf, (size_t)size);
+       full_write(dh->fd_write, buf, (size_t)size);
        security_stream_read(dh->netfd, process_writenetfd, dh);
     }
     else {
@@ -1281,8 +1482,8 @@ allocstream(
     /* allocate a stream from the security layer and return */
     dh->netfd = security_stream_server(as->security_handle);
     if (dh->netfd == NULL) {
-       dbprintf(("%s: couldn't open stream to server: %s\n",
-           debug_prefix_time(NULL), security_geterror(as->security_handle)));
+       dbprintf(_("couldn't open stream to server: %s\n"),
+           security_geterror(as->security_handle));
        return (-1);
     }
 
@@ -1300,11 +1501,12 @@ static struct active_service *
 service_new(
     security_handle_t *        security_handle,
     const char *       cmd,
+    service_t          service,
     const char *       arguments)
 {
     int i;
-    int data_read[DATA_FD_COUNT + 1][2];
-    int data_write[DATA_FD_COUNT + 1][2];
+    int data_read[DATA_FD_COUNT + 2][2];
+    int data_write[DATA_FD_COUNT + 2][2];
     struct active_service *as;
     pid_t pid;
     int newfd;
@@ -1314,33 +1516,48 @@ service_new(
     assert(arguments != NULL);
 
     /* a plethora of pipes */
+    /* data_read[0]                : stdin
+     * data_write[0]               : stdout
+     * data_read[1], data_write[1] : first  stream
+     * data_read[2], data_write[2] : second stream
+     * data_read[3], data_write[3] : third stream
+     * data_write[4]               : stderr
+     */
     for (i = 0; i < DATA_FD_COUNT + 1; i++) {
        if (pipe(data_read[i]) < 0) {
-           error("pipe: %s\n", strerror(errno));
+           error(_("pipe: %s\n"), strerror(errno));
            /*NOTREACHED*/
        }
        if (pipe(data_write[i]) < 0) {
-           error("pipe: %s\n", strerror(errno));
+           error(_("pipe: %s\n"), strerror(errno));
            /*NOTREACHED*/
        }
     }
+    if (pipe(data_write[STDERR_PIPE]) < 0) {
+       error(_("pipe: %s\n"), strerror(errno));
+       /*NOTREACHED*/
+    }
 
     switch(pid = fork()) {
     case -1:
-       error("could not fork service %s: %s\n", cmd, strerror(errno));
+       error(_("could not fork service %s: %s\n"), cmd, strerror(errno));
        /*NOTREACHED*/
     default:
        /*
         * The parent.  Close the far ends of our pipes and return.
         */
-       as = alloc(SIZEOF(*as));
+       as = g_new0(struct active_service, 1);
        as->cmd = stralloc(cmd);
        as->arguments = stralloc(arguments);
        as->security_handle = security_handle;
        as->state = NULL;
+       as->service = service;
        as->pid = pid;
        as->send_partial_reply = 0;
-       if(strcmp(cmd+(strlen(cmd)-8), "sendsize") == 0) {
+       as->seen_info_end = FALSE;
+       /* fill in info_end_buf with non-null characters */
+       memset(as->info_end_buf, '-', sizeof(as->info_end_buf));
+       if(service == SERVICE_SENDSIZE) {
            g_option_t *g_options;
            char *option_str, *p;
 
@@ -1372,6 +1589,14 @@ service_new(
        as->repretry = 0;
        as->rep_pkt.body = NULL;
 
+       /*
+        * read from the stderr pipe
+        */
+       as->errfd = data_write[STDERR_PIPE][0];
+       aclose(data_write[STDERR_PIPE][1]);
+       as->ev_errfd = NULL;
+       as->errbuf = NULL;
+
        /*
         * read from the rest of the general-use pipes
         * (netfds are opened as the client requests them)
@@ -1398,16 +1623,12 @@ service_new(
         * The child.  Put our pipes in their advertised locations
         * and start up.
         */
-#ifdef FORCE_USERID
-       seteuid((uid_t)0);
-       setuid(client_uid);
-#endif
 
        /*
         * The data stream is stdin in the new process
         */
         if (dup2(data_read[0][0], 0) < 0) {
-           error("dup %d to %d failed: %s\n", data_read[0][0], 0,
+           error(_("dup %d to %d failed: %s\n"), data_read[0][0], 0,
                strerror(errno));
            /*NOTREACHED*/
        }
@@ -1418,12 +1639,17 @@ service_new(
         * The reply stream is stdout
         */
         if (dup2(data_write[0][1], 1) < 0) {
-           error("dup %d to %d failed: %s\n", data_write[0][1], 1,
+           error(_("dup %d to %d failed: %s\n"), data_write[0][1], 1,
                strerror(errno));
        }
         aclose(data_write[0][0]);
         aclose(data_write[0][1]);
 
+       for (i = 0; i < DATA_FD_COUNT; i++) {
+           aclose(data_read[i + 1][0]);
+           aclose(data_write[i + 1][1]);
+       }
+
        /*
         *  Make sure they are not open in the range DATA_FD_OFFSET to
         *      DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1
@@ -1433,18 +1659,18 @@ service_new(
                  data_read[i + 1][1] <= DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1) {
                newfd = dup(data_read[i + 1][1]);
                if(newfd == -1)
-                   error("Can't dup out off DATA_FD range");
+                   error(_("Can't dup out off DATA_FD range"));
                data_read[i + 1][1] = newfd;
            }
            while(data_write[i + 1][0] >= DATA_FD_OFFSET &&
                  data_write[i + 1][0] <= DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1) {
                newfd = dup(data_write[i + 1][0]);
                if(newfd == -1)
-                   error("Can't dup out off DATA_FD range");
+                   error(_("Can't dup out off DATA_FD range"));
                data_write[i + 1][0] = newfd;
            }
        }
-       for (i = 0; i < DATA_FD_COUNT; i++)
+       for (i = 0; i < DATA_FD_COUNT*2; i++)
            close(DATA_FD_OFFSET + i);
 
        /*
@@ -1453,26 +1679,27 @@ service_new(
         */
        for (i = 0; i < DATA_FD_COUNT; i++) {
            if (dup2(data_read[i + 1][1], i*2 + DATA_FD_OFFSET) < 0) {
-               error("dup %d to %d failed: %s\n", data_read[i + 1][1],
+               error(_("dup %d to %d failed: %s\n"), data_read[i + 1][1],
                    i + DATA_FD_OFFSET, strerror(errno));
            }
-           aclose(data_read[i + 1][0]);
            aclose(data_read[i + 1][1]);
 
            if (dup2(data_write[i + 1][0], i*2 + 1 + DATA_FD_OFFSET) < 0) {
-               error("dup %d to %d failed: %s\n", data_write[i + 1][0],
+               error(_("dup %d to %d failed: %s\n"), data_write[i + 1][0],
                    i + DATA_FD_OFFSET, strerror(errno));
            }
            aclose(data_write[i + 1][0]);
-           aclose(data_write[i + 1][1]);
        }
 
        /* close all unneeded fd */
+       close(STDERR_FILENO);
+       dup2(data_write[STDERR_PIPE][1], 2);
+        aclose(data_write[STDERR_PIPE][0]);
+        aclose(data_write[STDERR_PIPE][1]);
        safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
-       close(2);
 
        execle(cmd, cmd, "amandad", auth, (char *)NULL, safe_env());
-       error("could not exec service %s: %s\n", cmd, strerror(errno));
+       error(_("could not exec service %s: %s\n"), cmd, strerror(errno));
        /*NOTREACHED*/
     }
     return NULL;
@@ -1488,10 +1715,8 @@ service_delete(
     int i;
     struct datafd_handle *dh;
 
-#ifdef AMANDAD_DEBUG
-       dbprintf(("%s: closing service: %s\n",
-           debug_prefix_time(NULL), (as->cmd)?as->cmd:"??UNKONWN??"));
-#endif
+    amandad_debug(1, _("closing service: %s\n"),
+                     (as->cmd)?as->cmd:_("??UNKONWN??"));
 
     assert(as != NULL);
 
@@ -1560,7 +1785,7 @@ writebuf(
     size_t                     size)
 {
     pid_t pid;
-    ssize_t    writesize;
+    size_t    writesize;
 
     switch (pid=fork()) {
     case -1:
@@ -1572,8 +1797,8 @@ writebuf(
 
     case 0:                            /* this is the child */
        close(as->repfd);
-       writesize = fullwrite(as->reqfd, bufp, size);
-       exit(writesize != (ssize_t)size);
+       writesize = full_write(as->reqfd, bufp, size);
+       exit(writesize != size);
        /* NOTREACHED */
     }
     return -1;
@@ -1584,12 +1809,14 @@ do_sendpkt(
     security_handle_t *        handle,
     pkt_t *            pkt)
 {
-    dbprintf(("%s: sending %s pkt:\n<<<<<\n%s>>>>>\n",
-       debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->body));
-    return security_sendpkt(handle, pkt);
+    dbprintf(_("sending %s pkt:\n<<<<<\n%s>>>>>\n"),
+       pkt_type2str(pkt->type), pkt->body);
+    if (handle)
+       return security_sendpkt(handle, pkt);
+    else
+       return 1;
 }
 
-#ifdef AMANDAD_DEBUG
 /*
  * Convert a state into a string
  */
@@ -1614,7 +1841,7 @@ state2str(
     for (i = 0; i < (int)(sizeof(states) / sizeof(states[0])); i++)
        if (state == states[i].state)
            return (states[i].str);
-    return ("INVALID STATE");
+    return (_("INVALID STATE"));
 }
 
 /*
@@ -1644,6 +1871,25 @@ action2str(
     for (i = 0; i < (int)(sizeof(actions) / sizeof(actions[0])); i++)
        if (action == actions[i].action)
            return (actions[i].str);
-    return ("UNKNOWN ACTION");
+    return (_("UNKNOWN ACTION"));
 }
-#endif /* AMANDAD_DEBUG */
+
+static char *
+amandad_get_security_conf(
+    char *      string,
+    void *      arg)
+{
+    (void)arg;      /* Quiet unused parameter warning */
+
+    if (!string || !*string)
+       return(NULL);
+
+    if (strcmp(string, "kencrypt")==0) {
+       if (amandad_kencrypt == KENCRYPT_YES)
+           return ("yes");
+       else
+           return (NULL);
+    }
+    return(NULL);
+}
+