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