430f2b7f6a5a33990c396891725f6a1f8f171e92
[debian/amanda] / amandad-src / amandad.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1999 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26
27 /*
28  * $Id: amandad.c,v 1.18 2006/08/21 20:17:09 martinea Exp $
29  *
30  * handle client-host side of Amanda network communications, including
31  * security checks, execution of the proper service, and acking the
32  * master side
33  */
34
35 #include "amanda.h"
36 #include "amandad.h"
37 #include "clock.h"
38 #include "event.h"
39 #include "amfeatures.h"
40 #include "packet.h"
41 #include "version.h"
42 #include "queue.h"
43 #include "security.h"
44 #include "stream.h"
45 #include "util.h"
46 #include "conffile.h"
47
48 #define REP_TIMEOUT     (6*60*60)       /* secs for service to reply */
49 #define ACK_TIMEOUT     10              /* XXX should be configurable */
50
51 #define amandad_debug(i, ...) do {      \
52         if ((i) <= debug_amandad) {     \
53                 dbprintf(__VA_ARGS__);  \
54         }                               \
55 } while (0)
56
57 /*
58  * These are the actions for entering the state machine
59  */
60 typedef enum { A_START, A_RECVPKT, A_RECVREP, A_PENDING, A_FINISH, A_CONTINUE,
61     A_SENDNAK, A_TIMEOUT } action_t;
62
63 /*
64  * This is a state in the state machine.  It is a function pointer to
65  * the function that actually implements the state.
66  */
67 struct active_service;
68 typedef action_t (*state_t)(struct active_service *, action_t, pkt_t *);
69
70 /*
71  * This structure describes an active running service.
72  *
73  * An active service is something running that we have received
74  * a request for.  This structure holds info on that service, including
75  * file descriptors for data, etc, as well as the security handle
76  * for communications with the amanda server.
77  */
78 struct active_service {
79     char *cmd;                          /* name of command we ran */
80     char *arguments;                    /* arguments we sent it */
81     security_handle_t *security_handle; /* remote server */
82     state_t state;                      /* how far this has progressed */
83     pid_t pid;                          /* pid of subprocess */
84     int send_partial_reply;             /* send PREP packet */
85     int reqfd;                          /* pipe to write requests */
86     int repfd;                          /* pipe to read replies */
87     event_handle_t *ev_repfd;           /* read event handle for repfd */
88     event_handle_t *ev_reptimeout;      /* timeout for rep data */
89     pkt_t rep_pkt;                      /* rep packet we're sending out */
90     char *repbuf;                       /* buffer to read the rep into */
91     size_t bufsize;                     /* length of repbuf */
92     size_t repbufsize;                  /* length of repbuf */
93     int repretry;                       /* times we'll retry sending the rep */
94     /*
95      * General user streams to the process, and their equivalent
96      * network streams.
97      */
98     struct datafd_handle {
99         int fd_read;                    /* pipe to child process */
100         int fd_write;                   /* pipe to child process */
101         event_handle_t *ev_read;        /* it's read event handle */
102         event_handle_t *ev_write;       /* it's write event handle */
103         security_stream_t *netfd;       /* stream to amanda server */
104         struct active_service *as;      /* pointer back to our enclosure */
105     } data[DATA_FD_COUNT];
106     char databuf[NETWORK_BLOCK_BYTES];  /* buffer to relay netfd data in */
107     TAILQ_ENTRY(active_service) tq;     /* queue handle */
108 };
109
110 /* 
111  * Here are the services that we allow.
112  */
113 static struct services {
114     char *name;
115     int  active;
116 } services[] = {
117     { "noop", 1 },
118     { "sendsize", 1 },
119     { "sendbackup", 1 },
120     { "selfcheck", 1 },
121     { "amindexd", 0 },
122     { "amidxtaped", 0 }
123 };
124 #define NSERVICES       (int)(sizeof(services) / sizeof(services[0]))
125
126 /*
127  * Queue of outstanding requests that we are running.
128  */
129 static struct {
130     TAILQ_HEAD(, active_service) tailq;
131     int qlength;
132 } serviceq = {
133     TAILQ_HEAD_INITIALIZER(serviceq.tailq), 0
134 };
135
136 static int wait_30s = 1;
137 static int exit_on_qlength = 1;
138 static char *auth = NULL;
139 static kencrypt_type amandad_kencrypt = KENCRYPT_NONE;
140
141 int main(int argc, char **argv);
142
143 static int allocstream(struct active_service *, int);
144 static void exit_check(void *);
145 static void protocol_accept(security_handle_t *, pkt_t *);
146 static void state_machine(struct active_service *, action_t, pkt_t *);
147
148 static action_t s_sendack(struct active_service *, action_t, pkt_t *);
149 static action_t s_repwait(struct active_service *, action_t, pkt_t *);
150 static action_t s_processrep(struct active_service *, action_t, pkt_t *);
151 static action_t s_sendrep(struct active_service *, action_t, pkt_t *);
152 static action_t s_ackwait(struct active_service *, action_t, pkt_t *);
153
154 static void repfd_recv(void *);
155 static void timeout_repfd(void *);
156 static void protocol_recv(void *, pkt_t *, security_status_t);
157 static void process_readnetfd(void *);
158 static void process_writenetfd(void *, void *, ssize_t);
159 static struct active_service *service_new(security_handle_t *,
160     const char *, const char *);
161 static void service_delete(struct active_service *);
162 static int writebuf(struct active_service *, const void *, size_t);
163 static ssize_t do_sendpkt(security_handle_t *handle, pkt_t *pkt);
164 static char *amandad_get_security_conf (char *, void *);
165
166 static const char *state2str(state_t);
167 static const char *action2str(action_t);
168
169 int
170 main(
171     int         argc,
172     char **     argv)
173 {
174     int i, j;
175     int have_services;
176     int in, out;
177     const security_driver_t *secdrv;
178     int no_exit = 0;
179     char *pgm = "amandad";              /* in case argv[0] is not set */
180 #if defined(USE_REUSEADDR)
181     const int on = 1;
182     int r;
183 #endif
184
185     /*
186      * Configure program for internationalization:
187      *   1) Only set the message locale for now.
188      *   2) Set textdomain for all amanda related programs to "amanda"
189      *      We don't want to be forced to support dozens of message catalogs.
190      */  
191     setlocale(LC_MESSAGES, "C");
192     textdomain("amanda"); 
193
194     safe_fd(-1, 0);
195     safe_cd();
196
197     /*
198      * When called via inetd, it is not uncommon to forget to put the
199      * argv[0] value on the config line.  On some systems (e.g. Solaris)
200      * this causes argv and/or argv[0] to be NULL, so we have to be
201      * careful getting our name.
202      */
203     if ((argv == NULL) || (argv[0] == NULL)) {
204             pgm = "amandad";            /* in case argv[0] is not set */
205     } else {
206             pgm = basename(argv[0]);    /* Strip of leading path get debug name */
207     }
208     set_pname(pgm);
209     dbopen(DBG_SUBDIR_AMANDAD);
210
211     if(argv == NULL) {
212         error(_("argv == NULL\n"));
213         /*NOTREACHED*/
214     }
215
216     /* Don't die when child closes pipe */
217     signal(SIGPIPE, SIG_IGN);
218
219     config_init(CONFIG_INIT_CLIENT, NULL);
220
221     if (geteuid() == 0) {
222         check_running_as(RUNNING_AS_ROOT);
223         initgroups(CLIENT_LOGIN, get_client_gid());
224         setgid(get_client_gid());
225         setegid(get_client_gid());
226         seteuid(get_client_uid());
227     } else {
228         check_running_as(RUNNING_AS_CLIENT_LOGIN);
229     }
230
231     erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
232
233     /*
234      * ad-hoc argument parsing
235      *
236      * We accept        -auth=[authentication type]
237      *                  -no-exit
238      *                  -tcp=[port]
239      *                  -udp=[port]
240      * We also add a list of services that amandad can launch
241      */
242     secdrv = NULL;
243     in = 0; out = 1;            /* default to stdin/stdout */
244     have_services = 0;
245     for (i = 1; i < argc; i++) {
246         /*
247          * accept -krb4 as an alias for -auth=krb4 (for compatibility)
248          */
249         if (strcmp(argv[i], "-krb4") == 0) {
250             argv[i] = "-auth=krb4";
251             /* FALLTHROUGH */
252             auth = "krb4";
253         }
254
255         /*
256          * Get a driver for a security type specified after -auth=
257          */
258         else if (strncmp(argv[i], "-auth=", strlen("-auth=")) == 0) {
259             argv[i] += strlen("-auth=");
260             secdrv = security_getdriver(argv[i]);
261             auth = argv[i];
262             if (secdrv == NULL) {
263                 error(_("no driver for security type '%s'\n"), argv[i]);
264                 /*NOTREACHED*/
265             }
266             continue;
267         }
268
269         /*
270          * If -no-exit is specified, always run even after requests have
271          * been satisfied.
272          */
273         else if (strcmp(argv[i], "-no-exit") == 0) {
274             no_exit = 1;
275             continue;
276         }
277
278         /*
279          * Allow us to directly bind to a udp port for debugging.
280          * This may only apply to some security types.
281          */
282         else if (strncmp(argv[i], "-udp=", strlen("-udp=")) == 0) {
283 #ifdef WORKING_IPV6
284             struct sockaddr_in6 sin;
285 #else
286             struct sockaddr_in sin;
287 #endif
288
289             argv[i] += strlen("-udp=");
290 #ifdef WORKING_IPV6
291             in = out = socket(AF_INET6, SOCK_DGRAM, 0);
292 #else
293             in = out = socket(AF_INET, SOCK_DGRAM, 0);
294 #endif
295             if (in < 0) {
296                 error(_("can't create dgram socket: %s\n"), strerror(errno));
297                 /*NOTREACHED*/
298             }
299 #ifdef USE_REUSEADDR
300             r = setsockopt(in, SOL_SOCKET, SO_REUSEADDR,
301                 (void *)&on, (socklen_t_equiv)sizeof(on));
302             if (r < 0) {
303                 dbprintf(_("amandad: setsockopt(SO_REUSEADDR) failed: %s\n"),
304                           strerror(errno));
305             }
306 #endif
307
308 #ifdef WORKING_IPV6
309             sin.sin6_family = (sa_family_t)AF_INET6;
310             sin.sin6_addr = in6addr_any;
311             sin.sin6_port = (in_port_t)htons((in_port_t)atoi(argv[i]));
312 #else
313             sin.sin_family = (sa_family_t)AF_INET;
314             sin.sin_addr.s_addr = INADDR_ANY;
315             sin.sin_port = (in_port_t)htons((in_port_t)atoi(argv[i]));
316 #endif
317             if (bind(in, (struct sockaddr *)&sin, (socklen_t_equiv)sizeof(sin)) < 0) {
318                 error(_("can't bind to port %d: %s\n"), atoi(argv[i]),
319                     strerror(errno));
320                 /*NOTREACHED*/
321             }
322         }
323         /*
324          * Ditto for tcp ports.
325          */
326         else if (strncmp(argv[i], "-tcp=", strlen("-tcp=")) == 0) {
327 #ifdef WORKING_IPV6
328             struct sockaddr_in6 sin;
329 #else
330             struct sockaddr_in sin;
331 #endif
332             int sock;
333             socklen_t_equiv n;
334
335             argv[i] += strlen("-tcp=");
336 #ifdef WORKING_IPV6
337             sock = socket(AF_INET6, SOCK_STREAM, 0);
338 #else
339             sock = socket(AF_INET, SOCK_STREAM, 0);
340 #endif
341             if (sock < 0) {
342                 error(_("can't create tcp socket: %s\n"), strerror(errno));
343                 /*NOTREACHED*/
344             }
345 #ifdef USE_REUSEADDR
346             r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
347                 (void *)&on, (socklen_t_equiv)sizeof(on));
348             if (r < 0) {
349                 dbprintf(_("amandad: setsockopt(SO_REUSEADDR) failed: %s\n"),
350                           strerror(errno));
351             }
352 #endif
353 #ifdef WORKING_IPV6
354             sin.sin6_family = (sa_family_t)AF_INET6;
355             sin.sin6_addr = in6addr_any;
356             sin.sin6_port = (in_port_t)htons((in_port_t)atoi(argv[i]));
357 #else
358             sin.sin_family = (sa_family_t)AF_INET;
359             sin.sin_addr.s_addr = INADDR_ANY;
360             sin.sin_port = (in_port_t)htons((in_port_t)atoi(argv[i]));
361 #endif
362             if (bind(sock, (struct sockaddr *)&sin, (socklen_t_equiv)sizeof(sin)) < 0) {
363                 error(_("can't bind to port %d: %s\n"), atoi(argv[i]),
364                     strerror(errno));
365                 /*NOTREACHED*/
366             }
367             listen(sock, 10);
368             n = (socklen_t_equiv)sizeof(sin);
369             in = out = accept(sock, (struct sockaddr *)&sin, &n);
370         }
371         /*
372          * It must be a service name
373          */
374         else {
375             /* clear all services */
376             if(!have_services) {
377                 for (j = 0; j < (int)NSERVICES; j++)
378                     services[j].active = 0;
379             }
380             have_services = 1;
381
382             if(strcmp(argv[i],"amdump") == 0) {
383                 services[0].active = 1;
384                 services[1].active = 1;
385                 services[2].active = 1;
386                 services[3].active = 1;
387             }
388             else {
389                 for (j = 0; j < (int)NSERVICES; j++)
390                     if (strcmp(services[j].name, argv[i]) == 0)
391                         break;
392                 if (j == (int)NSERVICES) {
393                     dbprintf(_("%s: invalid service\n"), argv[i]);
394                     exit(1);
395                 }
396                 services[j].active = 1;
397             }
398         }
399     }
400
401     /*
402      * If no security type specified, use BSD
403      */
404     if (secdrv == NULL) {
405         secdrv = security_getdriver("BSD");
406         auth = "bsd";
407         if (secdrv == NULL) {
408             error(_("no driver for default security type 'BSD'\n"));
409             /*NOTREACHED*/
410         }
411     }
412
413     if(strcasecmp(auth, "rsh") == 0 ||
414        strcasecmp(auth, "ssh") == 0 ||
415        strcasecmp(auth, "bsdtcp") == 0) {
416         wait_30s = 0;
417         exit_on_qlength = 1;
418     }
419
420     if (getuid() == 0) {
421         if (strcasecmp(auth, "krb5") != 0) {
422             error(_("Amanda must be run as user '%s' when using '%s' authetication"),
423                   CLIENT_LOGIN, auth);
424         }
425     } else {
426         if (strcasecmp(auth, "krb5") == 0) {
427             error(_("Amanda must be run as user 'root' when using 'krb5' authetication"));
428         }
429     }
430
431
432     /* initialize */
433
434     startclock();
435
436     dbprintf(_("version %s\n"), version());
437     for (i = 0; version_info[i] != NULL; i++) {
438         dbprintf("    %s", version_info[i]);
439     }
440
441     if (! (argc >= 1 && argv != NULL && argv[0] != NULL)) {
442         dbprintf(_("WARNING: argv[0] not defined: check inetd.conf\n"));
443     }
444
445     /* krb5 require the euid to be 0 */
446     if (strcasecmp(auth, "krb5") == 0) {
447         seteuid((uid_t)0);
448     }
449
450     /*
451      * Schedule to call protocol_accept() when new security handles
452      * are created on stdin.
453      */
454     security_accept(secdrv, amandad_get_security_conf, in, out, protocol_accept, NULL);
455
456     /*
457      * Schedule an event that will try to exit every 30 seconds if there
458      * are no requests outstanding.
459      */
460     if(wait_30s)
461         (void)event_register((event_id_t)30, EV_TIME, exit_check, &no_exit);
462
463     /*
464      * Call event_loop() with an arg of 0, telling it to block until all
465      * events are completed.
466      */
467     event_loop(0);
468
469     close(in);
470     close(out);
471     dbclose();
472     return(0);
473 }
474
475 /*
476  * This runs periodically and checks to see if we have any active services
477  * still running.  If we don't, then we quit.
478  */
479 static void
480 exit_check(
481     void *      cookie)
482 {
483     int no_exit;
484
485     assert(cookie != NULL);
486     no_exit = *(int *)cookie;
487
488     /*
489      * If things are still running, then don't exit.
490      */
491     if (serviceq.qlength > 0)
492         return;
493
494     /*
495      * If the caller asked us to never exit, then we're done
496      */
497     if (no_exit)
498         return;
499
500     dbclose();
501     exit(0);
502 }
503
504 /*
505  * Handles new incoming protocol handles.  This is a callback for
506  * security_accept(), which gets called when new handles are detected.
507  */
508 static void
509 protocol_accept(
510     security_handle_t * handle,
511     pkt_t *             pkt)
512 {
513     pkt_t pkt_out;
514     struct active_service *as;
515     char *pktbody, *tok, *service, *arguments;
516     char *service_path = NULL;
517     int i;
518
519     pkt_out.body = NULL;
520
521     /*
522      * If handle is NULL, then the connection is closed.
523      */
524     if(handle == NULL) {
525         return;
526     }
527
528     /*
529      * If pkt is NULL, then there was a problem with the new connection.
530      */
531     if (pkt == NULL) {
532         dbprintf(_("accept error: %s\n"), security_geterror(handle));
533         pkt_init(&pkt_out, P_NAK, "ERROR %s\n", security_geterror(handle));
534         do_sendpkt(handle, &pkt_out);
535         amfree(pkt_out.body);
536         security_close(handle);
537         return;
538     }
539
540     dbprintf(_("accept recv %s pkt:\n<<<<<\n%s>>>>>\n"),
541         pkt_type2str(pkt->type), pkt->body);
542
543     /*
544      * If this is not a REQ packet, just forget about it.
545      */
546     if (pkt->type != P_REQ) {
547         dbprintf(_("received unexpected %s packet:\n<<<<<\n%s>>>>>\n\n"),
548             pkt_type2str(pkt->type), pkt->body);
549         security_close(handle);
550         return;
551     }
552
553     pktbody = service = arguments = NULL;
554     as = NULL;
555
556     /*
557      * Parse out the service and arguments
558      */
559
560     pktbody = stralloc(pkt->body);
561
562     tok = strtok(pktbody, " ");
563     if (tok == NULL)
564         goto badreq;
565     if (strcmp(tok, "SERVICE") != 0)
566         goto badreq;
567
568     tok = strtok(NULL, " \n");
569     if (tok == NULL)
570         goto badreq;
571     service = stralloc(tok);
572
573     /* we call everything else 'arguments' */
574     tok = strtok(NULL, "");
575     if (tok == NULL)
576         goto badreq;
577     arguments = stralloc(tok);
578
579     /* see if it's one we allow */
580     for (i = 0; i < (int)NSERVICES; i++)
581         if (services[i].active == 1 && strcmp(services[i].name, service) == 0)
582             break;
583     if (i == (int)NSERVICES) {
584         dbprintf(_("%s: invalid service\n"), service);
585         pkt_init(&pkt_out, P_NAK, _("ERROR %s: invalid service, add '%s' as argument to amandad\n"), service, service);
586         goto send_pkt_out;
587     }
588
589     service_path = vstralloc(amlibexecdir, "/", service, versionsuffix(), NULL);
590     if (access(service_path, X_OK) < 0) {
591         dbprintf(_("can't execute %s: %s\n"), service_path, strerror(errno));
592             pkt_init(&pkt_out, P_NAK,
593                      _("ERROR execute access to \"%s\" denied\n"),
594                      service_path);
595         goto send_pkt_out;
596     }
597
598     /* see if its already running */
599     for (as = TAILQ_FIRST(&serviceq.tailq); as != NULL;
600         as = TAILQ_NEXT(as, tq)) {
601             if (strcmp(as->cmd, service_path) == 0 &&
602                 strcmp(as->arguments, arguments) == 0) {
603                     dbprintf(_("%s %s: already running, acking req\n"),
604                         service, arguments);
605                     pkt_init_empty(&pkt_out, P_ACK);
606                     goto send_pkt_out_no_delete;
607             }
608     }
609
610     /*
611      * create a new service instance, and send the arguments down
612      * the request pipe.
613      */
614     dbprintf(_("creating new service: %s\n%s\n"), service, arguments);
615     as = service_new(handle, service_path, arguments);
616     if (writebuf(as, arguments, strlen(arguments)) < 0) {
617         const char *errmsg = strerror(errno);
618         dbprintf(_("error sending arguments to %s: %s\n"), service, errmsg);
619         pkt_init(&pkt_out, P_NAK, _("ERROR error writing arguments to %s: %s\n"),
620             service, errmsg);
621         goto send_pkt_out;
622     }
623     aclose(as->reqfd);
624
625     amfree(pktbody);
626     amfree(service);
627     amfree(service_path);
628     amfree(arguments);
629
630     /*
631      * Move to the sendack state, and start up the state
632      * machine.
633      */
634     as->state = s_sendack;
635     state_machine(as, A_START, NULL);
636     return;
637
638 badreq:
639     pkt_init(&pkt_out, P_NAK, _("ERROR invalid REQ\n"));
640     dbprintf(_("received invalid %s packet:\n<<<<<\n%s>>>>>\n\n"),
641         pkt_type2str(pkt->type), pkt->body);
642
643 send_pkt_out:
644     if(as)
645         service_delete(as);
646 send_pkt_out_no_delete:
647     amfree(pktbody);
648     amfree(service_path);
649     amfree(service);
650     amfree(arguments);
651     do_sendpkt(handle, &pkt_out);
652     security_close(handle);
653     amfree(pkt_out.body);
654 }
655
656 /*
657  * Handles incoming protocol packets.  Routes responses to the proper
658  * running service.
659  */
660 static void
661 state_machine(
662     struct active_service *     as,
663     action_t                    action,
664     pkt_t *                     pkt)
665 {
666     action_t retaction;
667     state_t curstate;
668     pkt_t nak;
669
670     amandad_debug(1, _("state_machine: %p entering\n"), as);
671     for (;;) {
672         curstate = as->state;
673         amandad_debug(1, _("state_machine: %p curstate=%s action=%s\n"), as,
674                           state2str(curstate), action2str(action));
675         retaction = (*curstate)(as, action, pkt);
676         amandad_debug(1, _("state_machine: %p curstate=%s returned %s (nextstate=%s)\n"),
677                           as, state2str(curstate), action2str(retaction),
678                           state2str(as->state));
679
680         switch (retaction) {
681         /*
682          * State has queued up and is now blocking on input.
683          */
684         case A_PENDING:
685             amandad_debug(1, _("state_machine: %p leaving (A_PENDING)\n"), as);
686             return;
687
688         /*
689          * service has switched states.  Loop.
690          */
691         case A_CONTINUE:
692             break;
693
694         /*
695          * state has determined that the packet it received was bogus.
696          * Send a nak, and return.
697          */
698         case A_SENDNAK:
699             dbprintf(_("received unexpected %s packet\n"),
700                 pkt_type2str(pkt->type));
701             dbprintf(_("<<<<<\n%s----\n\n"), pkt->body);
702             pkt_init(&nak, P_NAK, _("ERROR unexpected packet type %s\n"),
703                 pkt_type2str(pkt->type));
704             do_sendpkt(as->security_handle, &nak);
705             amfree(nak.body);
706             security_recvpkt(as->security_handle, protocol_recv, as, -1);
707             amandad_debug(1, _("state_machine: %p leaving (A_SENDNAK)\n"), as);
708             return;
709
710         /*
711          * Service is done.  Remove it and finish.
712          */
713         case A_FINISH:
714             amandad_debug(1, _("state_machine: %p leaving (A_FINISH)\n"), as);
715             service_delete(as);
716             return;
717
718         default:
719             assert(0);
720             break;
721         }
722     }
723     /*NOTREACHED*/
724 }
725
726 /*
727  * This state just sends an ack.  After that, we move to the repwait
728  * state to wait for REP data to arrive from the subprocess.
729  */
730 static action_t
731 s_sendack(
732     struct active_service *     as,
733     action_t                    action,
734     pkt_t *                     pkt)
735 {
736     pkt_t ack;
737
738     (void)action;       /* Quiet unused parameter warning */
739     (void)pkt;          /* Quiet unused parameter warning */
740
741     pkt_init_empty(&ack, P_ACK);
742     if (do_sendpkt(as->security_handle, &ack) < 0) {
743         dbprintf(_("error sending ACK: %s\n"),
744             security_geterror(as->security_handle));
745         amfree(ack.body);
746         return (A_FINISH);
747     }
748     amfree(ack.body);
749
750     /*
751      * move to the repwait state
752      * Setup a listener for data on the reply fd, but also
753      * listen for packets over the wire, as the server may
754      * poll us if we take a long time.
755      * Setup a timeout that will fire if it takes too long to
756      * receive rep data.
757      */
758     as->state = s_repwait;
759     as->ev_repfd = event_register((event_id_t)as->repfd, EV_READFD, repfd_recv, as);
760     as->ev_reptimeout = event_register(REP_TIMEOUT, EV_TIME,
761         timeout_repfd, as);
762     security_recvpkt(as->security_handle, protocol_recv, as, -1);
763     return (A_PENDING);
764 }
765
766 /*
767  * This is the repwait state.  We have responded to the initial REQ with
768  * an ACK, and we are now waiting for the process we spawned to pass us 
769  * data to send in a REP.
770  */
771 static action_t
772 s_repwait(
773     struct active_service *     as,
774     action_t                    action,
775     pkt_t *                     pkt)
776 {
777     ssize_t   n;
778     char     *repbuf_temp;
779     char     *what;
780     char     *msg;
781     int       code = 0;
782     int       t;
783     int       pid;
784     amwait_t  retstat;
785
786     /*
787      * We normally shouldn't receive any packets while waiting
788      * for our REP data, but in some cases we do.
789      */
790     if (action == A_RECVPKT) {
791         assert(pkt != NULL);
792         /*
793          * Another req for something that's running.  Just send an ACK
794          * and go back and wait for more data.
795          */
796         if (pkt->type == P_REQ) {
797             dbprintf(_("received dup P_REQ packet, ACKing it\n"));
798             amfree(as->rep_pkt.body);
799             pkt_init_empty(&as->rep_pkt, P_ACK);
800             do_sendpkt(as->security_handle, &as->rep_pkt);
801             security_recvpkt(as->security_handle, protocol_recv, as, -1);
802             return (A_PENDING);
803         }
804         /* something unexpected.  Nak it */
805         return (A_SENDNAK);
806     }
807
808     if (action == A_TIMEOUT) {
809         amfree(as->rep_pkt.body);
810         pkt_init(&as->rep_pkt, P_NAK, _("ERROR timeout on reply pipe\n"));
811         dbprintf(_("%s timed out waiting for REP data\n"), as->cmd);
812         do_sendpkt(as->security_handle, &as->rep_pkt);
813         return (A_FINISH);
814     }
815
816     assert(action == A_RECVREP);
817     if(as->bufsize == 0) {
818         as->bufsize = NETWORK_BLOCK_BYTES;
819         as->repbuf = alloc(as->bufsize);
820     }
821
822     do {
823         n = read(as->repfd, as->repbuf + as->repbufsize,
824                  as->bufsize - as->repbufsize - 1);
825     } while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
826     if (n < 0) {
827         const char *errstr = strerror(errno);
828         dbprintf(_("read error on reply pipe: %s\n"), errstr);
829         amfree(as->rep_pkt.body);
830         pkt_init(&as->rep_pkt, P_NAK, _("ERROR read error on reply pipe: %s\n"),
831                  errstr);
832         do_sendpkt(as->security_handle, &as->rep_pkt);
833         return (A_FINISH);
834     }
835
836     /* If end of service, wait for process status */
837     if (n == 0) {
838         t = 0;
839         pid = waitpid(as->pid, &retstat, WNOHANG);
840         while (t<5 && pid == 0) {
841             sleep(1);
842             t++;
843             pid = waitpid(as->pid, &retstat, WNOHANG);
844         }
845
846         if (pid > 0) {
847             what = NULL;
848             if (! WIFEXITED(retstat)) {
849                 what = _("signal");
850                 code = WTERMSIG(retstat);
851             } else if (WEXITSTATUS(retstat) != 0) {
852                 what = _("code");
853                 code = WEXITSTATUS(retstat);
854             }
855             if (what) {
856                 dbprintf(_("service %s failed: pid %u exited with %s %d\n"),
857                          (as->cmd)?as->cmd:_("??UNKONWN??"),
858                          (unsigned)as->pid,
859                          what, code);
860                 msg = vstrallocf(
861                      _("ERROR service %s failed: pid %u exited with %s %d\n"),
862                      (as->cmd)?as->cmd:_("??UNKONWN??"), (unsigned)as->pid,
863                      what, code);
864                 if (as->repbufsize + strlen(msg) >= (as->bufsize - 1)) {
865                         as->bufsize *= 2;
866                         repbuf_temp = alloc(as->bufsize);
867                         memcpy(repbuf_temp, as->repbuf, as->repbufsize + 1);
868                         amfree(as->repbuf);
869                         as->repbuf = repbuf_temp;
870                 }
871                 strcpy(as->repbuf + as->repbufsize, msg);
872                 as->repbufsize += strlen(msg);
873             }
874         }
875     }
876
877     /*
878      * If we got some data, go back and wait for more, or EOF.  Nul terminate
879      * the buffer first.
880      */
881     as->repbuf[n + as->repbufsize] = '\0';
882     if (n > 0) {
883         as->repbufsize += n;
884         if(as->repbufsize >= (as->bufsize - 1)) {
885             as->bufsize *= 2;
886             repbuf_temp = alloc(as->bufsize);
887             memcpy(repbuf_temp, as->repbuf, as->repbufsize + 1);
888             amfree(as->repbuf);
889             as->repbuf = repbuf_temp;
890         }
891         else if(as->send_partial_reply) {
892             amfree(as->rep_pkt.body);
893             pkt_init(&as->rep_pkt, P_PREP, "%s", as->repbuf);
894             do_sendpkt(as->security_handle, &as->rep_pkt);
895             amfree(as->rep_pkt.body);
896             pkt_init_empty(&as->rep_pkt, P_REP);
897         }
898  
899         return (A_PENDING);
900     }
901
902     /*
903      * If we got 0, then we hit EOF.  Process the data and release
904      * the timeout.
905      */
906     assert(n == 0);
907
908     assert(as->ev_repfd != NULL);
909     event_release(as->ev_repfd);
910     as->ev_repfd = NULL;
911
912     assert(as->ev_reptimeout != NULL);
913     event_release(as->ev_reptimeout);
914     as->ev_reptimeout = NULL;
915
916     as->state = s_processrep;
917     aclose(as->repfd);
918     return (A_CONTINUE);
919 }
920
921 /*
922  * After we have read in all of the rep data, we process it and send
923  * it out as a REP packet.
924  */
925 static action_t
926 s_processrep(
927     struct active_service *     as,
928     action_t                    action,
929     pkt_t *                     pkt)
930 {
931     char *tok, *repbuf;
932
933     (void)action;       /* Quiet unused parameter warning */
934     (void)pkt;          /* Quiet unused parameter warning */
935
936     /*
937      * Copy the rep lines into the outgoing packet.
938      *
939      * If this line is a CONNECT, translate it
940      * Format is "CONNECT <tag> <handle> <tag> <handle> etc...
941      * Example:
942      *
943      *  CONNECT DATA 4 MESG 5 INDEX 6
944      *
945      * The tags are arbitrary.  The handles are in the DATA_FD pool.
946      * We need to map these to security streams and pass them back
947      * to the amanda server.  If the handle is -1, then we don't map.
948      */
949     if (strncmp_const(as->repbuf,"KENCRYPT\n") == 0) {
950         amandad_kencrypt = KENCRYPT_WILL_DO;
951         repbuf = stralloc(as->repbuf + 9);
952     } else {
953         repbuf = stralloc(as->repbuf);
954     }
955     amfree(as->rep_pkt.body);
956     pkt_init_empty(&as->rep_pkt, P_REP);
957     tok = strtok(repbuf, " ");
958     if (tok == NULL)
959         goto error;
960     if (strcmp(tok, "CONNECT") == 0) {
961         char *line, *nextbuf;
962
963         /* Save the entire line */
964         line = strtok(NULL, "\n");
965         /* Save the buf following the line */
966         nextbuf = strtok(NULL, "");
967
968         if (line == NULL || nextbuf == NULL)
969             goto error;
970
971         pkt_cat(&as->rep_pkt, "CONNECT");
972
973         /* loop over the id/handle pairs */
974         for (;;) {
975             /* id */
976             tok = strtok(line, " ");
977             line = NULL;        /* keep working from line */
978             if (tok == NULL)
979                 break;
980             pkt_cat(&as->rep_pkt, " %s", tok);
981
982             /* handle */
983             tok = strtok(NULL, " \n");
984             if (tok == NULL)
985                 goto error;
986             /* convert the handle into something the server can process */
987             pkt_cat(&as->rep_pkt, " %d", allocstream(as, atoi(tok)));
988         }
989         pkt_cat(&as->rep_pkt, "\n%s", nextbuf);
990     } else {
991 error:
992         pkt_cat(&as->rep_pkt, "%s", as->repbuf);
993     }
994
995     /*
996      * We've setup our REP packet in as->rep_pkt.  Now move to the transmission
997      * state.
998      */
999     as->state = s_sendrep;
1000     as->repretry = getconf_int(CNF_REP_TRIES);
1001     amfree(repbuf);
1002     return (A_CONTINUE);
1003 }
1004
1005 /*
1006  * This is the state where we send the REP we just collected from our child.
1007  */
1008 static action_t
1009 s_sendrep(
1010     struct active_service *     as,
1011     action_t                    action,
1012     pkt_t *                     pkt)
1013 {
1014     (void)action;       /* Quiet unused parameter warning */
1015     (void)pkt;          /* Quiet unused parameter warning */
1016
1017     /*
1018      * Transmit it and move to the ack state.
1019      */
1020     do_sendpkt(as->security_handle, &as->rep_pkt);
1021     security_recvpkt(as->security_handle, protocol_recv, as, ACK_TIMEOUT);
1022     as->state = s_ackwait;
1023     return (A_PENDING);
1024 }
1025
1026 /*
1027  * This is the state in which we wait for the server to ACK the REP
1028  * we just sent it.
1029  */
1030 static action_t
1031 s_ackwait(
1032     struct active_service *     as,
1033     action_t                    action,
1034     pkt_t *                     pkt)
1035 {
1036     struct datafd_handle *dh;
1037     int npipes;
1038
1039     /*
1040      * If we got a timeout, try again, but eventually give up.
1041      */
1042     if (action == A_TIMEOUT) {
1043         if (--as->repretry > 0) {
1044             as->state = s_sendrep;
1045             return (A_CONTINUE);
1046         }
1047         dbprintf(_("timeout waiting for ACK for our REP\n"));
1048         return (A_FINISH);
1049     }
1050     amandad_debug(1, _("received ACK, now opening streams\n"));
1051
1052     assert(action == A_RECVPKT);
1053
1054     if (pkt->type == P_REQ) {
1055         dbprintf(_("received dup P_REQ packet, resending REP\n"));
1056         as->state = s_sendrep;
1057         return (A_CONTINUE);
1058     }
1059
1060     if (pkt->type != P_ACK)
1061         return (A_SENDNAK);
1062
1063     if (amandad_kencrypt == KENCRYPT_WILL_DO) {
1064         amandad_kencrypt = KENCRYPT_YES;
1065     }
1066
1067     /*
1068      * Got the ack, now open the pipes
1069      */
1070     for (dh = &as->data[0]; dh < &as->data[DATA_FD_COUNT]; dh++) {
1071         if (dh->netfd == NULL)
1072             continue;
1073         if (security_stream_accept(dh->netfd) < 0) {
1074             dbprintf(_("stream %td accept failed: %s\n"),
1075                 dh - &as->data[0], security_geterror(as->security_handle));
1076             security_stream_close(dh->netfd);
1077             dh->netfd = NULL;
1078             continue;
1079         }
1080         /* setup an event for reads from it */
1081         dh->ev_read = event_register((event_id_t)dh->fd_read, EV_READFD,
1082                                      process_readnetfd, dh);
1083
1084         security_stream_read(dh->netfd, process_writenetfd, dh);
1085
1086     }
1087
1088     /*
1089      * Pipes are open, so auth them.  Count them at the same time.
1090      */
1091     for (npipes = 0, dh = &as->data[0]; dh < &as->data[DATA_FD_COUNT]; dh++) {
1092         if (dh->netfd == NULL)
1093             continue;
1094         if (security_stream_auth(dh->netfd) < 0) {
1095             security_stream_close(dh->netfd);
1096             dh->netfd = NULL;
1097             event_release(dh->ev_read);
1098             event_release(dh->ev_write);
1099             dh->ev_read = NULL;
1100             dh->ev_write = NULL;
1101         } else {
1102             npipes++;
1103         }
1104     }
1105
1106     /*
1107      * If no pipes are open, then we're done.  Otherwise, just start running.
1108      * The event handlers on all of the pipes will take it from here.
1109      */
1110     amandad_debug(1, _("at end of s_ackwait, npipes is %d\n"), npipes);
1111     if (npipes == 0)
1112         return (A_FINISH);
1113     else {
1114         security_close(as->security_handle);
1115         as->security_handle = NULL;
1116         return (A_PENDING);
1117     }
1118 }
1119
1120 /*
1121  * Called when a repfd has received data
1122  */
1123 static void
1124 repfd_recv(
1125     void *      cookie)
1126 {
1127     struct active_service *as = cookie;
1128
1129     assert(as != NULL);
1130     assert(as->ev_repfd != NULL);
1131
1132     state_machine(as, A_RECVREP, NULL);
1133 }
1134
1135 /*
1136  * Called when a repfd has timed out
1137  */
1138 static void
1139 timeout_repfd(
1140     void *      cookie)
1141 {
1142     struct active_service *as = cookie;
1143
1144     assert(as != NULL);
1145     assert(as->ev_reptimeout != NULL);
1146
1147     state_machine(as, A_TIMEOUT, NULL);
1148 }
1149
1150 /*
1151  * Called when a handle has received data
1152  */
1153 static void
1154 protocol_recv(
1155     void *              cookie,
1156     pkt_t *             pkt,
1157     security_status_t   status)
1158 {
1159     struct active_service *as = cookie;
1160
1161     assert(as != NULL);
1162
1163     switch (status) {
1164     case S_OK:
1165         dbprintf(_("received %s pkt:\n<<<<<\n%s>>>>>\n"),
1166             pkt_type2str(pkt->type), pkt->body);
1167         state_machine(as, A_RECVPKT, pkt);
1168         break;
1169     case S_TIMEOUT:
1170         dbprintf(_("timeout\n"));
1171         state_machine(as, A_TIMEOUT, NULL);
1172         break;
1173     case S_ERROR:
1174         dbprintf(_("receive error: %s\n"),
1175             security_geterror(as->security_handle));
1176         break;
1177     }
1178 }
1179
1180 /*
1181  * This is a generic relay function that just reads data from one of
1182  * the process's pipes and passes it up the equivalent security_stream_t
1183  */
1184 static void
1185 process_readnetfd(
1186     void *      cookie)
1187 {
1188     pkt_t nak;
1189     struct datafd_handle *dh = cookie;
1190     struct active_service *as = dh->as;
1191     ssize_t n;
1192
1193     nak.body = NULL;
1194
1195     do {
1196         n = read(dh->fd_read, as->databuf, SIZEOF(as->databuf));
1197     } while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
1198
1199     /*
1200      * Process has died.
1201      */
1202     if (n < 0) {
1203         pkt_init(&nak, P_NAK, _("A ERROR data descriptor %d broken: %s\n"),
1204             dh->fd_read, strerror(errno));
1205         goto sendnak;
1206     }
1207     /*
1208      * Process has closed the pipe.  Just remove this event handler.
1209      * If all pipes are closed, shut down this service.
1210      */
1211     if (n == 0) {
1212         event_release(dh->ev_read);
1213         dh->ev_read = NULL;
1214         if(dh->ev_write == NULL) {
1215             security_stream_close(dh->netfd);
1216             dh->netfd = NULL;
1217         }
1218         for (dh = &as->data[0]; dh < &as->data[DATA_FD_COUNT]; dh++) {
1219             if (dh->netfd != NULL)
1220                 return;
1221         }
1222         service_delete(as);
1223         return;
1224     }
1225     if (security_stream_write(dh->netfd, as->databuf, (size_t)n) < 0) {
1226         /* stream has croaked */
1227         pkt_init(&nak, P_NAK, _("ERROR write error on stream %d: %s\n"),
1228             security_stream_id(dh->netfd),
1229             security_stream_geterror(dh->netfd));
1230         goto sendnak;
1231     }
1232     return;
1233
1234 sendnak:
1235     do_sendpkt(as->security_handle, &nak);
1236     service_delete(as);
1237     amfree(nak.body);
1238 }
1239
1240 /*
1241  * This is a generic relay function that just read data from one of
1242  * the security_stream_t and passes it up the equivalent process's pipes
1243  */
1244 static void
1245 process_writenetfd(
1246     void *      cookie,
1247     void *      buf,
1248     ssize_t     size)
1249 {
1250     struct datafd_handle *dh;
1251
1252     assert(cookie != NULL);
1253     dh = cookie;
1254
1255     if (dh->fd_write <= 0) {
1256         dbprintf(_("process_writenetfd: dh->fd_write <= 0\n"));
1257     } else if (size > 0) {
1258         fullwrite(dh->fd_write, buf, (size_t)size);
1259         security_stream_read(dh->netfd, process_writenetfd, dh);
1260     }
1261     else {
1262         aclose(dh->fd_write);
1263     }
1264 }
1265
1266
1267 /*
1268  * Convert a local stream handle (DATA_FD...) into something that
1269  * can be sent to the amanda server.
1270  *
1271  * Returns a number that should be sent to the server in the REP packet.
1272  */
1273 static int
1274 allocstream(
1275     struct active_service *     as,
1276     int                         handle)
1277 {
1278     struct datafd_handle *dh;
1279
1280     /* if the handle is -1, then we don't bother */
1281     if (handle < 0)
1282         return (-1);
1283
1284     /* make sure the handle's kosher */
1285     if (handle < DATA_FD_OFFSET || handle >= DATA_FD_OFFSET + DATA_FD_COUNT)
1286         return (-1);
1287
1288     /* get a pointer into our handle array */
1289     dh = &as->data[handle - DATA_FD_OFFSET];
1290
1291     /* make sure we're not already using the net handle */
1292     if (dh->netfd != NULL)
1293         return (-1);
1294
1295     /* allocate a stream from the security layer and return */
1296     dh->netfd = security_stream_server(as->security_handle);
1297     if (dh->netfd == NULL) {
1298         dbprintf(_("couldn't open stream to server: %s\n"),
1299             security_geterror(as->security_handle));
1300         return (-1);
1301     }
1302
1303     /*
1304      * convert the stream into a numeric id that can be sent to the
1305      * remote end.
1306      */
1307     return (security_stream_id(dh->netfd));
1308 }
1309
1310 /*
1311  * Create a new service instance
1312  */
1313 static struct active_service *
1314 service_new(
1315     security_handle_t * security_handle,
1316     const char *        cmd,
1317     const char *        arguments)
1318 {
1319     int i;
1320     int data_read[DATA_FD_COUNT + 1][2];
1321     int data_write[DATA_FD_COUNT + 1][2];
1322     struct active_service *as;
1323     pid_t pid;
1324     int newfd;
1325
1326     assert(security_handle != NULL);
1327     assert(cmd != NULL);
1328     assert(arguments != NULL);
1329
1330     /* a plethora of pipes */
1331     for (i = 0; i < DATA_FD_COUNT + 1; i++) {
1332         if (pipe(data_read[i]) < 0) {
1333             error(_("pipe: %s\n"), strerror(errno));
1334             /*NOTREACHED*/
1335         }
1336         if (pipe(data_write[i]) < 0) {
1337             error(_("pipe: %s\n"), strerror(errno));
1338             /*NOTREACHED*/
1339         }
1340     }
1341
1342     switch(pid = fork()) {
1343     case -1:
1344         error(_("could not fork service %s: %s\n"), cmd, strerror(errno));
1345         /*NOTREACHED*/
1346     default:
1347         /*
1348          * The parent.  Close the far ends of our pipes and return.
1349          */
1350         as = alloc(SIZEOF(*as));
1351         as->cmd = stralloc(cmd);
1352         as->arguments = stralloc(arguments);
1353         as->security_handle = security_handle;
1354         as->state = NULL;
1355         as->pid = pid;
1356         as->send_partial_reply = 0;
1357         if(strcmp(cmd+(strlen(cmd)-8), "sendsize") == 0) {
1358             g_option_t *g_options;
1359             char *option_str, *p;
1360
1361             option_str = stralloc(as->arguments+8);
1362             p = strchr(option_str,'\n');
1363             if(p) *p = '\0';
1364
1365             g_options = parse_g_options(option_str, 1);
1366             if(am_has_feature(g_options->features, fe_partial_estimate)) {
1367                 as->send_partial_reply = 1;
1368             }
1369             free_g_options(g_options);
1370             amfree(option_str);
1371         }
1372
1373         /* write to the request pipe */
1374         aclose(data_read[0][0]);
1375         as->reqfd = data_read[0][1];
1376
1377         /*
1378          * read from the reply pipe
1379          */
1380         as->repfd = data_write[0][0];
1381         aclose(data_write[0][1]);
1382         as->ev_repfd = NULL;
1383         as->repbuf = NULL;
1384         as->repbufsize = 0;
1385         as->bufsize = 0;
1386         as->repretry = 0;
1387         as->rep_pkt.body = NULL;
1388
1389         /*
1390          * read from the rest of the general-use pipes
1391          * (netfds are opened as the client requests them)
1392          */
1393         for (i = 0; i < DATA_FD_COUNT; i++) {
1394             aclose(data_read[i + 1][1]);
1395             aclose(data_write[i + 1][0]);
1396             as->data[i].fd_read = data_read[i + 1][0];
1397             as->data[i].fd_write = data_write[i + 1][1];
1398             as->data[i].ev_read = NULL;
1399             as->data[i].ev_write = NULL;
1400             as->data[i].netfd = NULL;
1401             as->data[i].as = as;
1402         }
1403
1404         /* add it to the service queue */
1405         /* increment the active service count */
1406         TAILQ_INSERT_TAIL(&serviceq.tailq, as, tq);
1407         serviceq.qlength++;
1408
1409         return (as);
1410     case 0:
1411         /*
1412          * The child.  Put our pipes in their advertised locations
1413          * and start up.
1414          */
1415
1416         /*
1417          * The data stream is stdin in the new process
1418          */
1419         if (dup2(data_read[0][0], 0) < 0) {
1420             error(_("dup %d to %d failed: %s\n"), data_read[0][0], 0,
1421                 strerror(errno));
1422             /*NOTREACHED*/
1423         }
1424         aclose(data_read[0][0]);
1425         aclose(data_read[0][1]);
1426
1427         /*
1428          * The reply stream is stdout
1429          */
1430         if (dup2(data_write[0][1], 1) < 0) {
1431             error(_("dup %d to %d failed: %s\n"), data_write[0][1], 1,
1432                 strerror(errno));
1433         }
1434         aclose(data_write[0][0]);
1435         aclose(data_write[0][1]);
1436
1437         for (i = 0; i < DATA_FD_COUNT; i++) {
1438             aclose(data_read[i + 1][0]);
1439             aclose(data_write[i + 1][1]);
1440         }
1441
1442         /*
1443          *  Make sure they are not open in the range DATA_FD_OFFSET to
1444          *      DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1
1445          */
1446         for (i = 0; i < DATA_FD_COUNT; i++) {
1447             while(data_read[i + 1][1] >= DATA_FD_OFFSET &&
1448                   data_read[i + 1][1] <= DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1) {
1449                 newfd = dup(data_read[i + 1][1]);
1450                 if(newfd == -1)
1451                     error(_("Can't dup out off DATA_FD range"));
1452                 data_read[i + 1][1] = newfd;
1453             }
1454             while(data_write[i + 1][0] >= DATA_FD_OFFSET &&
1455                   data_write[i + 1][0] <= DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1) {
1456                 newfd = dup(data_write[i + 1][0]);
1457                 if(newfd == -1)
1458                     error(_("Can't dup out off DATA_FD range"));
1459                 data_write[i + 1][0] = newfd;
1460             }
1461         }
1462         for (i = 0; i < DATA_FD_COUNT*2; i++)
1463             close(DATA_FD_OFFSET + i);
1464
1465         /*
1466          * The rest start at the offset defined in amandad.h, and continue
1467          * through the internal defined.
1468          */
1469         for (i = 0; i < DATA_FD_COUNT; i++) {
1470             if (dup2(data_read[i + 1][1], i*2 + DATA_FD_OFFSET) < 0) {
1471                 error(_("dup %d to %d failed: %s\n"), data_read[i + 1][1],
1472                     i + DATA_FD_OFFSET, strerror(errno));
1473             }
1474             aclose(data_read[i + 1][1]);
1475
1476             if (dup2(data_write[i + 1][0], i*2 + 1 + DATA_FD_OFFSET) < 0) {
1477                 error(_("dup %d to %d failed: %s\n"), data_write[i + 1][0],
1478                     i + DATA_FD_OFFSET, strerror(errno));
1479             }
1480             aclose(data_write[i + 1][0]);
1481         }
1482
1483         /* close all unneeded fd */
1484         close(STDERR_FILENO);
1485         debug_dup_stderr_to_debug();
1486         safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
1487
1488         execle(cmd, cmd, "amandad", auth, (char *)NULL, safe_env());
1489         error(_("could not exec service %s: %s\n"), cmd, strerror(errno));
1490         /*NOTREACHED*/
1491     }
1492     return NULL;
1493 }
1494
1495 /*
1496  * Unallocate a service instance
1497  */
1498 static void
1499 service_delete(
1500     struct active_service *     as)
1501 {
1502     int i;
1503     struct datafd_handle *dh;
1504
1505     amandad_debug(1, _("closing service: %s\n"),
1506                       (as->cmd)?as->cmd:_("??UNKONWN??"));
1507
1508     assert(as != NULL);
1509
1510     assert(as->cmd != NULL);
1511     amfree(as->cmd);
1512
1513     assert(as->arguments != NULL);
1514     amfree(as->arguments);
1515
1516     if (as->reqfd != -1)
1517         aclose(as->reqfd);
1518     if (as->repfd != -1)
1519         aclose(as->repfd);
1520
1521     if (as->ev_repfd != NULL)
1522         event_release(as->ev_repfd);
1523     if (as->ev_reptimeout != NULL)
1524         event_release(as->ev_reptimeout);
1525
1526     for (i = 0; i < DATA_FD_COUNT; i++) {
1527         dh = &as->data[i];
1528
1529         aclose(dh->fd_read);
1530         aclose(dh->fd_write);
1531
1532         if (dh->netfd != NULL)
1533             security_stream_close(dh->netfd);
1534
1535         if (dh->ev_read != NULL)
1536             event_release(dh->ev_read);
1537         if (dh->ev_write != NULL)
1538             event_release(dh->ev_write);
1539     }
1540
1541     if (as->security_handle != NULL)
1542         security_close(as->security_handle);
1543
1544     assert(as->pid > 0);
1545     kill(as->pid, SIGTERM);
1546     waitpid(as->pid, NULL, WNOHANG);
1547
1548     TAILQ_REMOVE(&serviceq.tailq, as, tq);
1549     assert(serviceq.qlength > 0);
1550     serviceq.qlength--;
1551
1552     amfree(as->cmd);
1553     amfree(as->arguments);
1554     amfree(as->repbuf);
1555     amfree(as->rep_pkt.body);
1556     amfree(as);
1557
1558     if(exit_on_qlength == 0 && serviceq.qlength == 0) {
1559         dbclose();
1560         exit(0);
1561     }
1562 }
1563
1564 /*
1565  * Like 'fullwrite', but does the work in a child process so pipelines
1566  * do not hang.
1567  */
1568 static int
1569 writebuf(
1570     struct active_service *     as,
1571     const void *                bufp,
1572     size_t                      size)
1573 {
1574     pid_t pid;
1575     ssize_t    writesize;
1576
1577     switch (pid=fork()) {
1578     case -1:
1579         break;
1580
1581     default:
1582         waitpid(pid, NULL, WNOHANG);
1583         return 0;                       /* this is the parent */
1584
1585     case 0:                             /* this is the child */
1586         close(as->repfd);
1587         writesize = fullwrite(as->reqfd, bufp, size);
1588         exit(writesize != (ssize_t)size);
1589         /* NOTREACHED */
1590     }
1591     return -1;
1592 }
1593
1594 static ssize_t
1595 do_sendpkt(
1596     security_handle_t * handle,
1597     pkt_t *             pkt)
1598 {
1599     dbprintf(_("sending %s pkt:\n<<<<<\n%s>>>>>\n"),
1600         pkt_type2str(pkt->type), pkt->body);
1601     if (handle)
1602         return security_sendpkt(handle, pkt);
1603     else
1604         return 1;
1605 }
1606
1607 /*
1608  * Convert a state into a string
1609  */
1610 static const char *
1611 state2str(
1612     state_t     state)
1613 {
1614     static const struct {
1615         state_t state;
1616         const char str[13];
1617     } states[] = {
1618 #define X(state)        { state, stringize(state) }
1619         X(s_sendack),
1620         X(s_repwait),
1621         X(s_processrep),
1622         X(s_sendrep),
1623         X(s_ackwait),
1624 #undef X
1625     };
1626     int i;
1627
1628     for (i = 0; i < (int)(sizeof(states) / sizeof(states[0])); i++)
1629         if (state == states[i].state)
1630             return (states[i].str);
1631     return (_("INVALID STATE"));
1632 }
1633
1634 /*
1635  * Convert an action into a string
1636  */
1637 static const char *
1638 action2str(
1639     action_t    action)
1640 {
1641     static const struct {
1642         action_t action;
1643         const char str[12];
1644     } actions[] = {
1645 #define X(action)       { action, stringize(action) }
1646         X(A_START),
1647         X(A_RECVPKT),
1648         X(A_RECVREP),
1649         X(A_PENDING),
1650         X(A_FINISH),
1651         X(A_CONTINUE),
1652         X(A_SENDNAK),
1653         X(A_TIMEOUT),
1654 #undef X
1655     };
1656     int i;
1657
1658     for (i = 0; i < (int)(sizeof(actions) / sizeof(actions[0])); i++)
1659         if (action == actions[i].action)
1660             return (actions[i].str);
1661     return (_("UNKNOWN ACTION"));
1662 }
1663
1664 static char *
1665 amandad_get_security_conf(
1666     char *      string,
1667     void *      arg)
1668 {
1669     (void)arg;      /* Quiet unused parameter warning */
1670
1671     if (!string || !*string)
1672         return(NULL);
1673
1674     if (strcmp(string, "kencrypt")==0) {
1675         if (amandad_kencrypt == KENCRYPT_YES)
1676             return ("yes");
1677         else
1678             return (NULL);
1679     }
1680     return(NULL);
1681 }
1682