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