af14723c5dca9a547aba0c046edfc0f05e39dcc2
[debian/amanda] / server-src / dumper.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 /* $Id: dumper.c,v 1.190 2006/08/30 19:53:57 martinea Exp $
27  *
28  * requests remote amandad processes to dump filesystems
29  */
30 #include "amanda.h"
31 #include "amindex.h"
32 #include "arglist.h"
33 #include "clock.h"
34 #include "conffile.h"
35 #include "event.h"
36 #include "logfile.h"
37 #include "packet.h"
38 #include "protocol.h"
39 #include "security.h"
40 #include "stream.h"
41 #include "version.h"
42 #include "fileheader.h"
43 #include "amfeatures.h"
44 #include "server_util.h"
45 #include "util.h"
46 #include "timestamp.h"
47 #include "amxml.h"
48
49 #define dumper_debug(i,x) do {          \
50         if ((i) <= debug_dumper) {      \
51             dbprintf(x);                \
52         }                               \
53 } while (0)
54
55 #ifndef SEEK_SET
56 #define SEEK_SET 0
57 #endif
58
59 #ifndef SEEK_CUR
60 #define SEEK_CUR 1
61 #endif
62
63 #define CONNECT_TIMEOUT 5*60
64
65 #define STARTUP_TIMEOUT 60
66
67 struct databuf {
68     int fd;                     /* file to flush to */
69     char *buf;
70     char *datain;               /* data buffer markers */
71     char *dataout;
72     char *datalimit;
73     pid_t compresspid;          /* valid if fd is pipe to compress */
74     pid_t encryptpid;           /* valid if fd is pipe to encrypt */
75 };
76
77 static char *handle = NULL;
78
79 static char *errstr = NULL;
80 static off_t dumpbytes;
81 static off_t dumpsize, headersize, origsize;
82
83 static comp_t srvcompress = COMP_NONE;
84 char *srvcompprog = NULL;
85 char *clntcompprog = NULL;
86
87 static encrypt_t srvencrypt = ENCRYPT_NONE;
88 char *srv_encrypt = NULL;
89 char *clnt_encrypt = NULL;
90 char *srv_decrypt_opt = NULL;
91 char *clnt_decrypt_opt = NULL;
92 static kencrypt_type dumper_kencrypt;
93
94 static FILE *errf = NULL;
95 static char *hostname = NULL;
96 am_feature_t *their_features = NULL;
97 static char *diskname = NULL;
98 static char *qdiskname = NULL, *b64disk;
99 static char *device = NULL, *b64device;
100 static char *options = NULL;
101 static char *progname = NULL;
102 static char *amandad_path=NULL;
103 static char *client_username=NULL;
104 static char *ssh_keys=NULL;
105 static char *auth=NULL;
106 static int level;
107 static char *dumpdate = NULL;
108 static char *dumper_timestamp = NULL;
109 static time_t conf_dtimeout;
110 static int indexfderror;
111 static int set_datafd;
112 static char *dle_str = NULL;
113
114 static dumpfile_t file;
115
116 static struct {
117     const char *name;
118     security_stream_t *fd;
119 } streams[] = {
120 #define DATAFD  0
121     { "DATA", NULL },
122 #define MESGFD  1
123     { "MESG", NULL },
124 #define INDEXFD 2
125     { "INDEX", NULL },
126 };
127 #define NSTREAMS        (int)(sizeof(streams) / sizeof(streams[0]))
128
129 static am_feature_t *our_features = NULL;
130 static char *our_feature_string = NULL;
131
132 /* buffer to keep partial line from the MESG stream */
133 static struct {
134     char *buf;          /* buffer holding msg data */
135     size_t size;        /* size of alloced buffer */
136 } msg = { NULL, 0 };
137
138
139 /* local functions */
140 int             main(int, char **);
141 static int      do_dump(struct databuf *);
142 static void     check_options(char *);
143 static void     xml_check_options(char *optionstr);
144 static void     finish_tapeheader(dumpfile_t *);
145 static ssize_t  write_tapeheader(int, dumpfile_t *);
146 static void     databuf_init(struct databuf *, int);
147 static int      databuf_write(struct databuf *, const void *, size_t);
148 static int      databuf_flush(struct databuf *);
149 static void     process_dumpeof(void);
150 static void     process_dumpline(const char *);
151 static void     add_msg_data(const char *, size_t);
152 static void     parse_info_line(char *);
153 static void     log_msgout(logtype_t);
154 static char *   dumper_get_security_conf (char *, void *);
155
156 static int      runcompress(int, pid_t *, comp_t);
157 static int      runencrypt(int, pid_t *,  encrypt_t);
158
159 static void     sendbackup_response(void *, pkt_t *, security_handle_t *);
160 static int      startup_dump(const char *, const char *, const char *, int,
161                         const char *, const char *, const char *,
162                         const char *, const char *, const char *,
163                         const char *);
164 static void     stop_dump(void);
165
166 static void     read_indexfd(void *, void *, ssize_t);
167 static void     read_datafd(void *, void *, ssize_t);
168 static void     read_mesgfd(void *, void *, ssize_t);
169 static void     timeout(time_t);
170 static void     timeout_callback(void *);
171
172 static void
173 check_options(
174     char *options)
175 {
176   char *compmode = NULL;
177   char *compend  = NULL;
178   char *encryptmode = NULL;
179   char *encryptend = NULL;
180   char *decryptmode = NULL;
181   char *decryptend = NULL;
182
183     /* parse the compression option */
184     if (strstr(options, "srvcomp-best;") != NULL) 
185       srvcompress = COMP_BEST;
186     else if (strstr(options, "srvcomp-fast;") != NULL)
187       srvcompress = COMP_FAST;
188     else if ((compmode = strstr(options, "srvcomp-cust=")) != NULL) {
189         compend = strchr(compmode, ';');
190         if (compend ) {
191             srvcompress = COMP_SERVER_CUST;
192             *compend = '\0';
193             srvcompprog = stralloc(compmode + strlen("srvcomp-cust="));
194             *compend = ';';
195         }
196     } else if ((compmode = strstr(options, "comp-cust=")) != NULL) {
197         compend = strchr(compmode, ';');
198         if (compend) {
199             srvcompress = COMP_CUST;
200             *compend = '\0';
201             clntcompprog = stralloc(compmode + strlen("comp-cust="));
202             *compend = ';';
203         }
204     }
205     else {
206       srvcompress = COMP_NONE;
207     }
208     
209
210     /* now parse the encryption option */
211     if ((encryptmode = strstr(options, "encrypt-serv-cust=")) != NULL) {
212       encryptend = strchr(encryptmode, ';');
213       if (encryptend) {
214             srvencrypt = ENCRYPT_SERV_CUST;
215             *encryptend = '\0';
216             srv_encrypt = stralloc(encryptmode + strlen("encrypt-serv-cust="));
217             *encryptend = ';';
218       }
219     } else if ((encryptmode = strstr(options, "encrypt-cust=")) != NULL) {
220       encryptend = strchr(encryptmode, ';');
221       if (encryptend) {
222             srvencrypt = ENCRYPT_CUST;
223             *encryptend = '\0';
224             clnt_encrypt = stralloc(encryptmode + strlen("encrypt-cust="));
225             *encryptend = ';';
226       }
227     } else {
228       srvencrypt = ENCRYPT_NONE;
229     }
230     /* get the decryption option parameter */
231     if ((decryptmode = strstr(options, "server-decrypt-option=")) != NULL) {
232       decryptend = strchr(decryptmode, ';');
233       if (decryptend) {
234         *decryptend = '\0';
235         srv_decrypt_opt = stralloc(decryptmode + strlen("server-decrypt-option="));
236         *decryptend = ';';
237       }
238     } else if ((decryptmode = strstr(options, "client-decrypt-option=")) != NULL) {
239       decryptend = strchr(decryptmode, ';');
240       if (decryptend) {
241         *decryptend = '\0';
242         clnt_decrypt_opt = stralloc(decryptmode + strlen("client-decrypt-option="));
243         *decryptend = ';';
244       }
245     }
246
247     if (strstr(options, "kencrypt;") != NULL) {
248         dumper_kencrypt = KENCRYPT_WILL_DO;
249     } else {
250         dumper_kencrypt = KENCRYPT_NONE;
251     }
252 }
253
254
255 static void
256 xml_check_options(
257     char *optionstr)
258 {
259     char *o, *oo;
260     char *errmsg = NULL;
261     dle_t *dle;
262
263     char *uoptionstr = unquote_string(optionstr);
264     o = oo = vstralloc("<dle>", strchr(uoptionstr,'<'), "</dle>", NULL);
265   
266     dle = amxml_parse_node_CHAR(o, &errmsg);
267     if (dle == NULL) {
268         error("amxml_parse_node_CHAR failed: %s\n", errmsg);
269     }
270
271     if (dle->compress == COMP_SERVER_FAST) {
272         srvcompress = COMP_FAST;
273     } else if (dle->compress == COMP_SERVER_BEST) {
274         srvcompress = COMP_BEST;
275     } else if (dle->compress == COMP_SERVER_CUST) {
276         srvcompress = COMP_SERVER_CUST;
277         srvcompprog = dle->compprog;
278     } else if (dle->compress == COMP_CUST) {
279         srvcompress = COMP_CUST;
280         clntcompprog = dle->compprog;
281     } else {
282         srvcompress = COMP_NONE;
283     }
284
285     if (dle->encrypt == ENCRYPT_CUST) {
286         srvencrypt = ENCRYPT_CUST;
287         clnt_encrypt = dle->clnt_encrypt;
288         clnt_decrypt_opt = dle->clnt_decrypt_opt;
289     } else if (dle->encrypt == ENCRYPT_SERV_CUST) {
290         srvencrypt = ENCRYPT_SERV_CUST;
291         srv_encrypt = dle->clnt_encrypt;
292         srv_decrypt_opt = dle->clnt_decrypt_opt;
293     } else {
294         srvencrypt = ENCRYPT_NONE;
295     }
296 }
297
298
299 int
300 main(
301     int         argc,
302     char **     argv)
303 {
304     static struct databuf db;
305     struct cmdargs *cmdargs = NULL;
306     int outfd = -1;
307     int rc;
308     in_port_t taper_port;
309     char *q = NULL;
310     int a;
311     int res;
312     config_overwrites_t *cfg_ovr = NULL;
313     char *cfg_opt = NULL;
314     int dumper_setuid;
315
316     /*
317      * Configure program for internationalization:
318      *   1) Only set the message locale for now.
319      *   2) Set textdomain for all amanda related programs to "amanda"
320      *      We don't want to be forced to support dozens of message catalogs.
321      */  
322     setlocale(LC_MESSAGES, "C");
323     textdomain("amanda"); 
324
325     /* drop root privileges */
326     dumper_setuid = set_root_privs(0);
327
328     safe_fd(-1, 0);
329
330     set_pname("dumper");
331
332     dbopen(DBG_SUBDIR_SERVER);
333
334     /* Don't die when child closes pipe */
335     signal(SIGPIPE, SIG_IGN);
336
337     erroutput_type = (ERR_AMANDALOG|ERR_INTERACTIVE);
338     set_logerror(logerror);
339
340     cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
341     if (argc > 1)
342         cfg_opt = argv[1];
343     config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
344     apply_config_overwrites(cfg_ovr);
345
346     if (!dumper_setuid) {
347         error(_("dumper must be run setuid root"));
348     }
349
350     if (config_errors(NULL) >= CFGERR_ERRORS) {
351         g_critical(_("errors processing config file"));
352     }
353
354     safe_cd(); /* do this *after* config_init() */
355
356     check_running_as(RUNNING_AS_DUMPUSER);
357
358     dbrename(get_config_name(), DBG_SUBDIR_SERVER);
359
360     our_features = am_init_feature_set();
361     our_feature_string = am_feature_to_string(our_features);
362
363     log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
364     g_fprintf(stderr,
365             _("%s: pid %ld executable %s version %s\n"),
366             get_pname(), (long) getpid(),
367             argv[0], version());
368     fflush(stderr);
369
370     /* now, make sure we are a valid user */
371
372     signal(SIGPIPE, SIG_IGN);
373
374     conf_dtimeout = (time_t)getconf_int(CNF_DTIMEOUT);
375
376     protocol_init();
377
378     do {
379         if (cmdargs)
380             free_cmdargs(cmdargs);
381         cmdargs = getcmd();
382
383         amfree(errstr);
384         switch(cmdargs->cmd) {
385         case START:
386             if(cmdargs->argc <  2)
387                 error(_("error [dumper START: not enough args: timestamp]"));
388             dumper_timestamp = newstralloc(dumper_timestamp, cmdargs->argv[1]);
389             break;
390
391         case ABORT:
392             break;
393
394         case QUIT:
395             break;
396
397         case PORT_DUMP:
398             /*
399              * PORT-DUMP
400              *   handle
401              *   port
402              *   host
403              *   features
404              *   disk
405              *   device
406              *   level
407              *   dumpdate
408              *   progname
409              *   amandad_path
410              *   client_username
411              *   ssh_keys
412              *   security_driver
413              *   options
414              */
415             a = 1; /* skip "PORT-DUMP" */
416
417             if(a >= cmdargs->argc) {
418                 error(_("error [dumper PORT-DUMP: not enough args: handle]"));
419                 /*NOTREACHED*/
420             }
421             handle = newstralloc(handle, cmdargs->argv[a++]);
422
423             if(a >= cmdargs->argc) {
424                 error(_("error [dumper PORT-DUMP: not enough args: port]"));
425                 /*NOTREACHED*/
426             }
427             taper_port = (in_port_t)atoi(cmdargs->argv[a++]);
428
429             if(a >= cmdargs->argc) {
430                 error(_("error [dumper PORT-DUMP: not enough args: hostname]"));
431                 /*NOTREACHED*/
432             }
433             hostname = newstralloc(hostname, cmdargs->argv[a++]);
434
435             if(a >= cmdargs->argc) {
436                 error(_("error [dumper PORT-DUMP: not enough args: features]"));
437                 /*NOTREACHED*/
438             }
439             am_release_feature_set(their_features);
440             their_features = am_string_to_feature(cmdargs->argv[a++]);
441
442             if(a >= cmdargs->argc) {
443                 error(_("error [dumper PORT-DUMP: not enough args: diskname]"));
444                 /*NOTREACHED*/
445             }
446             diskname = newstralloc(diskname, cmdargs->argv[a++]);
447             if (qdiskname != NULL)
448                 amfree(qdiskname);
449             qdiskname = quote_string(diskname);
450             b64disk = amxml_format_tag("disk", diskname);
451
452             if(a >= cmdargs->argc) {
453                 error(_("error [dumper PORT-DUMP: not enough args: device]"));
454                 /*NOTREACHED*/
455             }
456             device = newstralloc(device, cmdargs->argv[a++]);
457             b64device = amxml_format_tag("diskdevice", device);
458             if(strcmp(device,"NODEVICE") == 0)
459                 amfree(device);
460
461             if(a >= cmdargs->argc) {
462                 error(_("error [dumper PORT-DUMP: not enough args: level]"));
463                 /*NOTREACHED*/
464             }
465             level = atoi(cmdargs->argv[a++]);
466
467             if(a >= cmdargs->argc) {
468                 error(_("error [dumper PORT-DUMP: not enough args: dumpdate]"));
469                 /*NOTREACHED*/
470             }
471             dumpdate = newstralloc(dumpdate, cmdargs->argv[a++]);
472
473             if(a >= cmdargs->argc) {
474                 error(_("error [dumper PORT-DUMP: not enough args: program]"));
475                 /*NOTREACHED*/
476             }
477             progname = newstralloc(progname, cmdargs->argv[a++]);
478
479             if(a >= cmdargs->argc) {
480                 error(_("error [dumper PORT-DUMP: not enough args: amandad_path]"));
481                 /*NOTREACHED*/
482             }
483             amandad_path = newstralloc(amandad_path, cmdargs->argv[a++]);
484
485             if(a >= cmdargs->argc) {
486                 error(_("error [dumper PORT-DUMP: not enough args: client_username]"));
487             }
488             client_username = newstralloc(client_username, cmdargs->argv[a++]);
489
490             if(a >= cmdargs->argc) {
491                 error(_("error [dumper PORT-DUMP: not enough args: ssh_keys]"));
492             }
493             ssh_keys = newstralloc(ssh_keys, cmdargs->argv[a++]);
494
495             if(a >= cmdargs->argc) {
496                 error(_("error [dumper PORT-DUMP: not enough args: auth]"));
497             }
498             auth = newstralloc(auth, cmdargs->argv[a++]);
499
500             if(a >= cmdargs->argc) {
501                 error(_("error [dumper PORT-DUMP: not enough args: options]"));
502             }
503             options = newstralloc(options, cmdargs->argv[a++]);
504
505             if(a != cmdargs->argc) {
506                 error(_("error [dumper PORT-DUMP: too many args: %d != %d]"),
507                       cmdargs->argc, a);
508                 /*NOTREACHED*/
509             }
510
511             /* Double-check that 'localhost' resolves properly */
512             if ((res = resolve_hostname("localhost", 0, NULL, NULL) != 0)) {
513                 errstr = newvstrallocf(errstr,
514                                      _("could not resolve localhost: %s"),
515                                      gai_strerror(res));
516                 q = quote_string(errstr);
517                 putresult(FAILED, "%s %s\n", handle, q);
518                 log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname,
519                         dumper_timestamp, level, errstr);
520                 amfree(q);
521                 break;
522             }
523
524             /* connect outf to chunker/taper port */
525
526             outfd = stream_client("localhost", taper_port,
527                                   STREAM_BUFSIZE, 0, NULL, 0);
528             if (outfd == -1) {
529                 
530                 errstr = newvstrallocf(errstr, _("port open: %s"),
531                                       strerror(errno));
532                 q = quote_string(errstr);
533                 putresult(FAILED, "%s %s\n", handle, q);
534                 log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname,
535                         dumper_timestamp, level, errstr);
536                 amfree(q);
537                 break;
538             }
539             databuf_init(&db, outfd);
540
541             if (am_has_feature(their_features, fe_req_xml))
542                 xml_check_options(options);
543             else
544                 check_options(options);
545
546             rc = startup_dump(hostname,
547                               diskname,
548                               device,
549                               level,
550                               dumpdate,
551                               progname,
552                               amandad_path,
553                               client_username,
554                               ssh_keys,
555                               auth,
556                               options);
557             if (rc != 0) {
558                 q = quote_string(errstr);
559                 putresult(rc == 2? FAILED : TRYAGAIN, "%s %s\n",
560                     handle, q);
561                 if (rc == 2)
562                     log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname,
563                         dumper_timestamp, level, errstr);
564                 amfree(q);
565             } else {
566                 do_dump(&db);
567                 /* try to clean up any defunct processes, since Amanda doesn't
568                    wait() for them explicitly */
569                 while(waitpid(-1, NULL, WNOHANG)> 0);
570             }
571
572             amfree(amandad_path);
573             amfree(client_username);
574
575             break;
576
577         default:
578             if(cmdargs->argc >= 1) {
579                 q = quote_string(cmdargs->argv[0]);
580             } else {
581                 q = stralloc(_("(no input?)"));
582             }
583             putresult(BAD_COMMAND, "%s\n", q);
584             amfree(q);
585             break;
586         }
587
588         if (outfd != -1)
589             aclose(outfd);
590     } while(cmdargs->cmd != QUIT);
591     free_cmdargs(cmdargs);
592
593     log_add(L_INFO, "pid-done %ld", (long)getpid());
594
595     am_release_feature_set(our_features);
596     amfree(our_feature_string);
597     amfree(errstr);
598     amfree(dumper_timestamp);
599     amfree(handle);
600     amfree(hostname);
601     amfree(qdiskname);
602     amfree(diskname);
603     amfree(device);
604     amfree(dumpdate);
605     amfree(progname);
606     amfree(srvcompprog);
607     amfree(clntcompprog);
608     amfree(srv_encrypt);
609     amfree(clnt_encrypt);
610     amfree(srv_decrypt_opt);
611     amfree(clnt_decrypt_opt);
612     amfree(options);
613
614     dbclose();
615     return (0); /* exit */
616 }
617
618
619 /*
620  * Initialize a databuf.  Takes a writeable file descriptor.
621  */
622 static void
623 databuf_init(
624     struct databuf *    db,
625     int                 fd)
626 {
627
628     db->fd = fd;
629     db->datain = db->dataout = db->datalimit = NULL;
630     db->compresspid = -1;
631     db->encryptpid = -1;
632 }
633
634
635 /*
636  * Updates the buffer pointer for the input data buffer.  The buffer is
637  * written regardless of how much data is present, since we know we
638  * are writing to a socket (to chunker) and there is no need to maintain
639  * any boundaries.
640  */
641 static int
642 databuf_write(
643     struct databuf *    db,
644     const void *        buf,
645     size_t              size)
646 {
647     db->buf = (char *)buf;
648     db->datain = db->datalimit = db->buf + size;
649     db->dataout = db->buf;
650     return databuf_flush(db);
651 }
652
653 /*
654  * Write out the buffer to chunker.
655  */
656 static int
657 databuf_flush(
658     struct databuf *    db)
659 {
660     size_t written;
661     char *m;
662
663     /*
664      * If there's no data, do nothing.
665      */
666     if (db->dataout >= db->datain) {
667         return 0;
668     }
669
670     /*
671      * Write out the buffer
672      */
673     written = full_write(db->fd, db->dataout,
674                         (size_t)(db->datain - db->dataout));
675     if (written > 0) {
676         db->dataout += written;
677         dumpbytes += (off_t)written;
678     }
679     if (dumpbytes >= (off_t)1024) {
680         dumpsize += (dumpbytes / (off_t)1024);
681         dumpbytes %= (off_t)1024;
682     }
683     if (written == 0) {
684         m = vstrallocf(_("data write: %s"), strerror(errno));
685         errstr = quote_string(m);
686         amfree(m);
687         return -1;
688     }
689     db->datain = db->dataout = db->buf;
690     return 0;
691 }
692
693 static int dump_result;
694 static int status;
695 #define GOT_INFO_ENDLINE        (1 << 0)
696 #define GOT_SIZELINE            (1 << 1)
697 #define GOT_ENDLINE             (1 << 2)
698 #define HEADER_DONE             (1 << 3)
699
700
701 static void
702 process_dumpeof(void)
703 {
704     /* process any partial line in msgbuf? !!! */
705     add_msg_data(NULL, 0);
706     if(!ISSET(status, GOT_SIZELINE) && dump_result < 2) {
707         /* make a note if there isn't already a failure */
708         g_fprintf(errf,
709                 _("? %s: strange [missing size line from sendbackup]\n"),
710                 get_pname());
711         if(errstr == NULL) {
712             errstr = stralloc(_("missing size line from sendbackup"));
713         }
714         dump_result = max(dump_result, 2);
715     }
716
717     if(!ISSET(status, GOT_ENDLINE) && dump_result < 2) {
718         g_fprintf(errf,
719                 _("? %s: strange [missing end line from sendbackup]\n"),
720                 get_pname());
721         if(errstr == NULL) {
722             errstr = stralloc(_("missing end line from sendbackup"));
723         }
724         dump_result = max(dump_result, 2);
725     }
726 }
727
728 /*
729  * Parse an information line from the client.
730  * We ignore unknown parameters and only remember the last
731  * of any duplicates.
732  */
733 static void
734 parse_info_line(
735     char *str)
736 {
737     static const struct {
738         const char *name;
739         char *value;
740         size_t len;
741     } fields[] = {
742         { "BACKUP", file.program, SIZEOF(file.program) },
743         { "APPLICATION", file.application, SIZEOF(file.application) },
744         { "RECOVER_CMD", file.recover_cmd, SIZEOF(file.recover_cmd) },
745         { "COMPRESS_SUFFIX", file.comp_suffix, SIZEOF(file.comp_suffix) },
746         { "SERVER_CUSTOM_COMPRESS", file.srvcompprog, SIZEOF(file.srvcompprog) },
747         { "CLIENT_CUSTOM_COMPRESS", file.clntcompprog, SIZEOF(file.clntcompprog) },
748         { "SERVER_ENCRYPT", file.srv_encrypt, SIZEOF(file.srv_encrypt) },
749         { "CLIENT_ENCRYPT", file.clnt_encrypt, SIZEOF(file.clnt_encrypt) },
750         { "SERVER_DECRYPT_OPTION", file.srv_decrypt_opt, SIZEOF(file.srv_decrypt_opt) },
751         { "CLIENT_DECRYPT_OPTION", file.clnt_decrypt_opt, SIZEOF(file.clnt_decrypt_opt) }
752     };
753     char *name, *value;
754     size_t i;
755
756     if (strcmp(str, "end") == 0) {
757         SET(status, GOT_INFO_ENDLINE);
758         return;
759     }
760
761     name = strtok(str, "=");
762     if (name == NULL)
763         return;
764     value = strtok(NULL, "");
765     if (value == NULL)
766         return;
767
768     for (i = 0; i < SIZEOF(fields) / SIZEOF(fields[0]); i++) {
769         if (strcmp(name, fields[i].name) == 0) {
770             strncpy(fields[i].value, value, fields[i].len - 1);
771             fields[i].value[fields[i].len - 1] = '\0';
772             break;
773         }
774     }
775 }
776
777 static void
778 process_dumpline(
779     const char *        str)
780 {
781     char *buf, *tok;
782
783     buf = stralloc(str);
784
785     switch (*buf) {
786     case '|':
787         /* normal backup output line */
788         break;
789     case '?':
790         /* sendbackup detected something strange */
791         dump_result = max(dump_result, 1);
792         break;
793     case 's':
794         /* a sendbackup line, just check them all since there are only 5 */
795         tok = strtok(buf, " ");
796         if (tok == NULL || strcmp(tok, "sendbackup:") != 0)
797             goto bad_line;
798
799         tok = strtok(NULL, " ");
800         if (tok == NULL)
801             goto bad_line;
802
803         if (strcmp(tok, "start") == 0) {
804             break;
805         }
806
807         if (strcmp(tok, "size") == 0) {
808             tok = strtok(NULL, "");
809             if (tok != NULL) {
810                 origsize = OFF_T_ATOI(tok);
811                 SET(status, GOT_SIZELINE);
812             }
813             break;
814         }
815
816         if (strcmp(tok, "end") == 0) {
817             SET(status, GOT_ENDLINE);
818             break;
819         }
820
821         if (strcmp(tok, "warning") == 0) {
822             dump_result = max(dump_result, 1);
823             break;
824         }
825
826         if (strcmp(tok, "error") == 0) {
827             SET(status, GOT_ENDLINE);
828             dump_result = max(dump_result, 2);
829
830             tok = strtok(NULL, "");
831             if (!errstr) { /* report first error line */
832                 if (tok == NULL || *tok != '[') {
833                     errstr = newvstrallocf(errstr, _("bad remote error: %s"),
834                                            str);
835                 } else {
836                     char *enderr;
837
838                     tok++;      /* skip over '[' */
839                     if ((enderr = strchr(tok, ']')) != NULL)
840                         *enderr = '\0';
841                     errstr = newstralloc(errstr, tok);
842                 }
843             }
844             break;
845         }
846
847         if (strcmp(tok, "info") == 0) {
848             tok = strtok(NULL, "");
849             if (tok != NULL)
850                 parse_info_line(tok);
851             break;
852         }
853         /* else we fall through to bad line */
854     default:
855 bad_line:
856         /* prefix with ?? */
857         g_fprintf(errf, "??");
858         dump_result = max(dump_result, 1);
859         break;
860     }
861     g_fprintf(errf, "%s\n", str);
862     amfree(buf);
863 }
864
865 static void
866 add_msg_data(
867     const char *        str,
868     size_t              len)
869 {
870     char *line, *ch;
871     size_t buflen;
872
873     if (msg.buf != NULL)
874         buflen = strlen(msg.buf);
875     else
876         buflen = 0;
877
878     /*
879      * If our argument is NULL, then we need to flush out any remaining
880      * bits and return.
881      */
882     if (str == NULL) {
883         if (buflen == 0)
884             return;
885         g_fprintf(errf,_("? %s: error [partial line in msgbuf: %zu bytes]\n"),
886             get_pname(), buflen);
887         g_fprintf(errf,_("? %s: error [partial line in msgbuf: \"%s\"]\n"),
888             get_pname(), msg.buf);
889         msg.buf[0] = '\0';
890         return;
891     }
892
893     /*
894      * Expand the buffer if it can't hold the new contents.
895      */
896     if ((buflen + len + 1) > msg.size) {
897         char *newbuf;
898         size_t newsize;
899
900 /* round up to next y, where y is a power of 2 */
901 #define ROUND(x, y)     (((x) + (y) - 1) & ~((y) - 1))
902
903         newsize = ROUND(buflen + (ssize_t)len + 1, 256);
904         newbuf = alloc(newsize);
905
906         if (msg.buf != NULL) {
907             strncpy(newbuf, msg.buf, newsize);
908             amfree(msg.buf);
909         } else
910             newbuf[0] = '\0';
911         msg.buf = newbuf;
912         msg.size = newsize;
913     }
914
915     /*
916      * If there was a partial line from the last call, then
917      * append the new data to the end.
918      */
919     strncat(msg.buf, str, len);
920
921     /*
922      * Process all lines in the buffer
923      * scanning line for unqouted newline.
924      */
925     for (ch = line = msg.buf; *ch != '\0'; ch++) {
926         if (*ch == '\n') {
927             /*
928              * Found a newline.  Terminate and process line.
929              */
930             *ch = '\0';
931             process_dumpline(line);
932             line = ch + 1;
933         }
934     }
935
936     /*
937      * If we did not process all of the data, move it to the front
938      * of the buffer so it is there next time.
939      */
940     if (*line != '\0') {
941         buflen = strlen(line);
942         memmove(msg.buf, line, (size_t)buflen + 1);
943     } else {
944         msg.buf[0] = '\0';
945     }
946 }
947
948
949 static void
950 log_msgout(
951     logtype_t   typ)
952 {
953     char *line;
954
955     fflush(errf);
956     if (fseek(errf, 0L, SEEK_SET) < 0) {
957         dbprintf(_("log_msgout: warning - seek failed: %s\n"), strerror(errno));
958     }
959     while ((line = agets(errf)) != NULL) {
960         if (line[0] != '\0') {
961                 log_add(typ, "%s", line);
962         }
963         amfree(line);
964     }
965
966     afclose(errf);
967 }
968
969 /* ------------- */
970
971 /*
972  * Fill in the rest of the tape header
973  */
974 static void
975 finish_tapeheader(
976     dumpfile_t *file)
977 {
978
979     assert(ISSET(status, HEADER_DONE));
980
981     file->type = F_DUMPFILE;
982     strncpy(file->datestamp, dumper_timestamp, sizeof(file->datestamp) - 1);
983     strncpy(file->name, hostname, SIZEOF(file->name) - 1);
984     strncpy(file->disk, diskname, SIZEOF(file->disk) - 1);
985     file->dumplevel = level;
986     file->blocksize = DISK_BLOCK_BYTES;
987
988     /*
989      * If we're doing the compression here, we need to override what
990      * sendbackup told us the compression was.
991      */
992     if (srvcompress != COMP_NONE) {
993         file->compressed = 1;
994 #ifndef UNCOMPRESS_OPT
995 #define UNCOMPRESS_OPT  ""
996 #endif
997         if (srvcompress == COMP_SERVER_CUST) {
998             g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
999                      " %s %s |", srvcompprog, "-d");
1000             strncpy(file->comp_suffix, "cust", SIZEOF(file->comp_suffix) - 1);
1001             file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
1002             strncpy(file->srvcompprog, srvcompprog, SIZEOF(file->srvcompprog) - 1);
1003             file->srvcompprog[SIZEOF(file->srvcompprog) - 1] = '\0';
1004         } else if ( srvcompress == COMP_CUST ) {
1005             g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
1006                      " %s %s |", clntcompprog, "-d");
1007             strncpy(file->comp_suffix, "cust", SIZEOF(file->comp_suffix) - 1);
1008             file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
1009             strncpy(file->clntcompprog, clntcompprog, SIZEOF(file->clntcompprog));
1010             file->clntcompprog[SIZEOF(file->clntcompprog) - 1] = '\0';
1011         } else {
1012             g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
1013                 " %s %s |", UNCOMPRESS_PATH, UNCOMPRESS_OPT);
1014             strncpy(file->comp_suffix, COMPRESS_SUFFIX,SIZEOF(file->comp_suffix) - 1);
1015             file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
1016         }
1017     } else {
1018         if (file->comp_suffix[0] == '\0') {
1019             file->compressed = 0;
1020             assert(SIZEOF(file->comp_suffix) >= 2);
1021             strncpy(file->comp_suffix, "N", SIZEOF(file->comp_suffix) - 1);
1022             file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
1023         } else {
1024             file->compressed = 1;
1025         }
1026     }
1027     /* take care of the encryption header here */
1028     if (srvencrypt != ENCRYPT_NONE) {
1029       file->encrypted= 1;
1030       if (srvencrypt == ENCRYPT_SERV_CUST) {
1031         g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
1032                  " %s %s |", srv_encrypt, srv_decrypt_opt); 
1033         strncpy(file->encrypt_suffix, "enc", SIZEOF(file->encrypt_suffix) - 1);
1034         file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0';
1035         strncpy(file->srv_encrypt, srv_encrypt, SIZEOF(file->srv_encrypt) - 1);
1036         file->srv_encrypt[SIZEOF(file->srv_encrypt) - 1] = '\0';
1037         strncpy(file->srv_decrypt_opt, srv_decrypt_opt, SIZEOF(file->srv_decrypt_opt) - 1);
1038         file->srv_decrypt_opt[SIZEOF(file->srv_decrypt_opt) - 1] = '\0';
1039       } else if ( srvencrypt == ENCRYPT_CUST ) {
1040         g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
1041                  " %s %s |", clnt_encrypt, clnt_decrypt_opt);
1042         strncpy(file->encrypt_suffix, "enc", SIZEOF(file->encrypt_suffix) - 1);
1043         file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0';
1044         strncpy(file->clnt_encrypt, clnt_encrypt, SIZEOF(file->clnt_encrypt) - 1);
1045         file->clnt_encrypt[SIZEOF(file->clnt_encrypt) - 1] = '\0';
1046         strncpy(file->clnt_decrypt_opt, clnt_decrypt_opt, SIZEOF(file->clnt_decrypt_opt));
1047         file->clnt_decrypt_opt[SIZEOF(file->clnt_decrypt_opt) - 1] = '\0';
1048       }
1049     } else {
1050       if (file->encrypt_suffix[0] == '\0') {
1051         file->encrypted = 0;
1052         assert(SIZEOF(file->encrypt_suffix) >= 2);
1053         strncpy(file->encrypt_suffix, "N", SIZEOF(file->encrypt_suffix) - 1);
1054         file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0';
1055       } else {
1056         file->encrypted= 1;
1057       }
1058     }
1059     if (dle_str)
1060         file->dle_str = stralloc(dle_str);
1061     else
1062         file->dle_str = NULL;
1063 }
1064
1065 /*
1066  * Send an Amanda dump header to the output file.
1067  */
1068 static ssize_t
1069 write_tapeheader(
1070     int         outfd,
1071     dumpfile_t *file)
1072 {
1073     char * buffer;
1074     size_t written;
1075
1076     buffer = build_header(file, DISK_BLOCK_BYTES);
1077
1078     written = full_write(outfd, buffer, DISK_BLOCK_BYTES);
1079     amfree(buffer);
1080     if(written == DISK_BLOCK_BYTES)
1081         return 0;
1082
1083     return -1;
1084 }
1085
1086 static int
1087 do_dump(
1088     struct databuf *db)
1089 {
1090     char *indexfile_tmp = NULL;
1091     char *indexfile_real = NULL;
1092     char level_str[NUM_STR_SIZE];
1093     char *fn;
1094     char *q;
1095     times_t runtime;
1096     double dumptime;    /* Time dump took in secs */
1097     char *errfname = NULL;
1098     int indexout;
1099     pid_t indexpid = -1;
1100     char *m;
1101
1102     startclock();
1103
1104     if (msg.buf) msg.buf[0] = '\0';     /* reset msg buffer */
1105     status = 0;
1106     dump_result = 0;
1107     dumpbytes = dumpsize = headersize = origsize = (off_t)0;
1108     fh_init(&file);
1109
1110     g_snprintf(level_str, SIZEOF(level_str), "%d", level);
1111     fn = sanitise_filename(diskname);
1112     errfname = newvstralloc(errfname,
1113                             AMANDA_TMPDIR,
1114                             "/", hostname,
1115                             ".", fn,
1116                             ".", level_str,
1117                             ".errout",
1118                             NULL);
1119     amfree(fn);
1120     if((errf = fopen(errfname, "w+")) == NULL) {
1121         errstr = newvstrallocf(errstr, "errfile open \"%s\": %s",
1122                               errfname, strerror(errno));
1123         amfree(errfname);
1124         goto failed;
1125     }
1126     unlink(errfname);                           /* so it goes away on close */
1127     amfree(errfname);
1128
1129     if (streams[INDEXFD].fd != NULL) {
1130         indexfile_real = getindexfname(hostname, diskname, dumper_timestamp, level);
1131         indexfile_tmp = stralloc2(indexfile_real, ".tmp");
1132
1133         if (mkpdir(indexfile_tmp, 0755, (uid_t)-1, (gid_t)-1) == -1) {
1134            errstr = newvstrallocf(errstr,
1135                                  _("err create %s: %s"),
1136                                  indexfile_tmp,
1137                                  strerror(errno));
1138            amfree(indexfile_real);
1139            amfree(indexfile_tmp);
1140            goto failed;
1141         }
1142         indexout = open(indexfile_tmp, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1143         if (indexout == -1) {
1144             errstr = newvstrallocf(errstr, _("err open %s: %s"),
1145                         indexfile_tmp, strerror(errno));
1146             goto failed;
1147         } else {
1148             if (runcompress(indexout, &indexpid, COMP_BEST) < 0) {
1149                 aclose(indexout);
1150                 goto failed;
1151             }
1152         }
1153         indexfderror = 0;
1154         /*
1155          * Schedule the indexfd for relaying to the index file
1156          */
1157         security_stream_read(streams[INDEXFD].fd, read_indexfd, &indexout);
1158     }
1159
1160     /*
1161      * We only need to process messages initially.  Once we have done
1162      * the header, we will start processing data too.
1163      */
1164     security_stream_read(streams[MESGFD].fd, read_mesgfd, db);
1165     set_datafd = 0;
1166
1167     /*
1168      * Setup a read timeout
1169      */
1170     timeout(conf_dtimeout);
1171
1172     /*
1173      * Start the event loop.  This will exit when all three events
1174      * (read the mesgfd, read the datafd, and timeout) are removed.
1175      */
1176     event_loop(0);
1177
1178     if (!ISSET(status, HEADER_DONE)) {
1179         dump_result = max(dump_result, 2);
1180         if (!errstr) errstr = stralloc(_("got no header information"));
1181     }
1182
1183     dumpsize -= headersize;             /* don't count the header */
1184     if (dumpsize <= (off_t)0) {
1185         dumpsize = (off_t)0;
1186         dump_result = max(dump_result, 2);
1187         if (!errstr) errstr = stralloc(_("got no data"));
1188     }
1189
1190     if (!ISSET(status, HEADER_DONE)) {
1191         dump_result = max(dump_result, 2);
1192         if (!errstr) errstr = stralloc(_("got no header information"));
1193     }
1194
1195     if (dumpsize == 0) {
1196         dump_result = max(dump_result, 2);
1197         if (!errstr) errstr = stralloc(_("got no data"));
1198     }
1199
1200     if (dump_result > 1)
1201         goto failed;
1202
1203     runtime = stopclock();
1204     dumptime = g_timeval_to_double(runtime);
1205
1206     amfree(errstr);
1207     errstr = alloc(128);
1208     g_snprintf(errstr, 128, _("sec %s kb %lld kps %3.1lf orig-kb %lld"),
1209         walltime_str(runtime),
1210         (long long)dumpsize,
1211         (isnormal(dumptime) ? ((double)dumpsize / (double)dumptime) : 0.0),
1212         (long long)origsize);
1213     m = vstrallocf("[%s]", errstr);
1214     q = quote_string(m);
1215     amfree(m);
1216     putresult(DONE, _("%s %lld %lld %lu %s\n"), handle,
1217                 (long long)origsize,
1218                 (long long)dumpsize,
1219                 (unsigned long)((double)dumptime+0.5), q);
1220     amfree(q);
1221
1222     switch(dump_result) {
1223     case 0:
1224         log_add(L_SUCCESS, "%s %s %s %d [%s]", hostname, qdiskname, dumper_timestamp, level, errstr);
1225
1226         break;
1227
1228     case 1:
1229         log_start_multiline();
1230         log_add(L_STRANGE, "%s %s %d [%s]", hostname, qdiskname, level, errstr);
1231         log_msgout(L_STRANGE);
1232         log_end_multiline();
1233
1234         break;
1235     }
1236
1237     if (errf) afclose(errf);
1238
1239     aclose(db->fd);
1240     if (indexfile_tmp) {
1241         amwait_t index_status;
1242
1243         /*@i@*/ aclose(indexout);
1244         waitpid(indexpid,&index_status,0);
1245         log_add(L_INFO, "pid-done %ld", (long)indexpid);
1246         if (rename(indexfile_tmp, indexfile_real) != 0) {
1247             log_add(L_WARNING, _("could not rename \"%s\" to \"%s\": %s"),
1248                     indexfile_tmp, indexfile_real, strerror(errno));
1249         }
1250         amfree(indexfile_tmp);
1251         amfree(indexfile_real);
1252     }
1253
1254     if(db->compresspid != -1) {
1255         waitpid(db->compresspid,NULL,0);
1256         log_add(L_INFO, "pid-done %ld", (long)db->compresspid);
1257     }
1258     if(db->encryptpid != -1) {
1259         waitpid(db->encryptpid,NULL,0);
1260         log_add(L_INFO, "pid-done %ld", (long)db->encryptpid);
1261     }
1262
1263     amfree(errstr);
1264     dumpfile_free_data(&file);
1265
1266     return 1;
1267
1268 failed:
1269     m = vstrallocf("[%s]", errstr);
1270     q = quote_string(m);
1271     putresult(FAILED, "%s %s\n", handle, q);
1272     amfree(q);
1273     amfree(m);
1274
1275     aclose(db->fd);
1276     /* kill all child process */
1277     if (db->compresspid != -1) {
1278         g_fprintf(stderr,_("%s: kill compress command\n"),get_pname());
1279         if (kill(db->compresspid, SIGTERM) < 0) {
1280             if (errno != ESRCH) {
1281                 g_fprintf(stderr,_("%s: can't kill compress command: %s\n"), 
1282                     get_pname(), strerror(errno));
1283             } else {
1284                 log_add(L_INFO, "pid-done %ld", (long)db->compresspid);
1285             }
1286         }
1287         else {
1288             waitpid(db->compresspid,NULL,0);
1289             log_add(L_INFO, "pid-done %ld", (long)db->compresspid);
1290         }
1291     }
1292
1293     if (db->encryptpid != -1) {
1294         g_fprintf(stderr,_("%s: kill encrypt command\n"),get_pname());
1295         if (kill(db->encryptpid, SIGTERM) < 0) {
1296             if (errno != ESRCH) {
1297                 g_fprintf(stderr,_("%s: can't kill encrypt command: %s\n"), 
1298                     get_pname(), strerror(errno));
1299             } else {
1300                 log_add(L_INFO, "pid-done %ld", (long)db->encryptpid);
1301             }
1302         }
1303         else {
1304             waitpid(db->encryptpid,NULL,0);
1305             log_add(L_INFO, "pid-done %ld", (long)db->encryptpid);
1306         }
1307     }
1308
1309     if (indexpid != -1) {
1310         g_fprintf(stderr,_("%s: kill index command\n"),get_pname());
1311         if (kill(indexpid, SIGTERM) < 0) {
1312             if (errno != ESRCH) {
1313                 g_fprintf(stderr,_("%s: can't kill index command: %s\n"), 
1314                     get_pname(),strerror(errno));
1315             } else {
1316                 log_add(L_INFO, "pid-done %ld", (long)indexpid);
1317             }
1318         }
1319         else {
1320             waitpid(indexpid,NULL,0);
1321             log_add(L_INFO, "pid-done %ld", (long)indexpid);
1322         }
1323     }
1324
1325     log_start_multiline();
1326     log_add(L_FAIL, _("%s %s %s %d [%s]"), hostname, qdiskname, dumper_timestamp,
1327             level, errstr);
1328     if (errf) {
1329         log_msgout(L_FAIL);
1330     }
1331     log_end_multiline();
1332
1333     if (errf) afclose(errf);
1334
1335     if (indexfile_tmp) {
1336         unlink(indexfile_tmp);
1337         amfree(indexfile_tmp);
1338         amfree(indexfile_real);
1339     }
1340
1341     return 0;
1342 }
1343
1344 /*
1345  * Callback for reads on the mesgfd stream
1346  */
1347 static void
1348 read_mesgfd(
1349     void *      cookie,
1350     void *      buf,
1351     ssize_t     size)
1352 {
1353     struct databuf *db = cookie;
1354
1355     assert(db != NULL);
1356
1357     switch (size) {
1358     case -1:
1359         errstr = newvstrallocf(errstr, _("mesg read: %s"),
1360             security_stream_geterror(streams[MESGFD].fd));
1361         dump_result = 2;
1362         stop_dump();
1363         return;
1364
1365     case 0:
1366         /*
1367          * EOF.  Just shut down the mesg stream.
1368          */
1369         process_dumpeof();
1370         security_stream_close(streams[MESGFD].fd);
1371         streams[MESGFD].fd = NULL;
1372         /*
1373          * If the data fd and index fd has also shut down, then we're done.
1374          */
1375         if ((set_datafd == 0 || streams[DATAFD].fd == NULL) && 
1376             streams[INDEXFD].fd == NULL)
1377             stop_dump();
1378         return;
1379
1380     default:
1381         assert(buf != NULL);
1382         add_msg_data(buf, (size_t)size);
1383         security_stream_read(streams[MESGFD].fd, read_mesgfd, cookie);
1384         break;
1385     }
1386
1387     if (ISSET(status, GOT_INFO_ENDLINE) && !ISSET(status, HEADER_DONE)) {
1388         SET(status, HEADER_DONE);
1389         /* time to do the header */
1390         finish_tapeheader(&file);
1391         if (write_tapeheader(db->fd, &file)) {
1392             errstr = newvstrallocf(errstr, _("write_tapeheader: %s"), 
1393                                   strerror(errno));
1394             dump_result = 2;
1395             stop_dump();
1396             return;
1397         }
1398         dumpsize += (off_t)DISK_BLOCK_KB;
1399         headersize += (off_t)DISK_BLOCK_KB;
1400
1401         if (srvencrypt == ENCRYPT_SERV_CUST) {
1402             if (runencrypt(db->fd, &db->encryptpid, srvencrypt) < 0) {
1403                 dump_result = 2;
1404                 stop_dump();
1405                 return;
1406             }
1407         }
1408         /*
1409          * Now, setup the compress for the data output, and start
1410          * reading the datafd.
1411          */
1412         if ((srvcompress != COMP_NONE) && (srvcompress != COMP_CUST)) {
1413             if (runcompress(db->fd, &db->compresspid, srvcompress) < 0) {
1414                 dump_result = 2;
1415                 stop_dump();
1416                 return;
1417             }
1418         }
1419         security_stream_read(streams[DATAFD].fd, read_datafd, db);
1420         set_datafd = 1;
1421     }
1422
1423     /*
1424      * Reset the timeout for future reads
1425      */
1426     timeout(conf_dtimeout);
1427 }
1428
1429 /*
1430  * Callback for reads on the datafd stream
1431  */
1432 static void
1433 read_datafd(
1434     void *      cookie,
1435     void *      buf,
1436     ssize_t     size)
1437 {
1438     struct databuf *db = cookie;
1439
1440     assert(db != NULL);
1441
1442     /*
1443      * The read failed.  Error out
1444      */
1445     if (size < 0) {
1446         errstr = newvstrallocf(errstr, _("data read: %s"),
1447             security_stream_geterror(streams[DATAFD].fd));
1448         dump_result = 2;
1449         stop_dump();
1450         return;
1451     }
1452
1453     /* The header had better be written at this point */
1454     assert(ISSET(status, HEADER_DONE));
1455
1456     /*
1457      * EOF.  Stop and return.
1458      */
1459     if (size == 0) {
1460         databuf_flush(db);
1461         if (dumpbytes != (off_t)0) {
1462             dumpsize += (off_t)1;
1463         }
1464         security_stream_close(streams[DATAFD].fd);
1465         streams[DATAFD].fd = NULL;
1466         /*
1467          * If the mesg fd and index fd has also shut down, then we're done.
1468          */
1469         if (streams[MESGFD].fd == NULL && streams[INDEXFD].fd == NULL)
1470             stop_dump();
1471         return;
1472     }
1473
1474     /*
1475      * We read something.  Add it to the databuf and reschedule for
1476      * more data.
1477      */
1478     assert(buf != NULL);
1479     if (databuf_write(db, buf, (size_t)size) < 0) {
1480         errstr = newvstrallocf(errstr, _("data write: %s"), strerror(errno));
1481         dump_result = 2;
1482         stop_dump();
1483         return;
1484     }
1485
1486     /*
1487      * Reset the timeout for future reads
1488      */
1489     timeout(conf_dtimeout);
1490
1491     security_stream_read(streams[DATAFD].fd, read_datafd, cookie);
1492 }
1493
1494 /*
1495  * Callback for reads on the index stream
1496  */
1497 static void
1498 read_indexfd(
1499     void *      cookie,
1500     void *      buf,
1501     ssize_t     size)
1502 {
1503     int fd;
1504
1505     assert(cookie != NULL);
1506     fd = *(int *)cookie;
1507
1508     if (size < 0) {
1509         errstr = newvstrallocf(errstr, _("index read: %s"),
1510             security_stream_geterror(streams[INDEXFD].fd));
1511         dump_result = 2;
1512         stop_dump();
1513         return;
1514     }
1515
1516     /*
1517      * EOF.  Stop and return.
1518      */
1519     if (size == 0) {
1520         security_stream_close(streams[INDEXFD].fd);
1521         streams[INDEXFD].fd = NULL;
1522         /*
1523          * If the mesg fd has also shut down, then we're done.
1524          */
1525         if ((set_datafd == 0 || streams[DATAFD].fd == NULL) &&
1526              streams[MESGFD].fd == NULL)
1527             stop_dump();
1528         return;
1529     }
1530
1531     assert(buf != NULL);
1532
1533     /*
1534      * We ignore error while writing to the index file.
1535      */
1536     if (full_write(fd, buf, (size_t)size) < (size_t)size) {
1537         /* Ignore error, but schedule another read. */
1538         if(indexfderror == 0) {
1539             indexfderror = 1;
1540             log_add(L_INFO, _("Index corrupted for %s:%s"), hostname, qdiskname);
1541         }
1542     }
1543     security_stream_read(streams[INDEXFD].fd, read_indexfd, cookie);
1544 }
1545
1546 /*
1547  * Startup a timeout in the event handler.  If the arg is 0,
1548  * then remove the timeout.
1549  */
1550 static void
1551 timeout(
1552     time_t seconds)
1553 {
1554     static event_handle_t *ev_timeout = NULL;
1555
1556     /*
1557      * First, remove a timeout if one is active.
1558      */
1559     if (ev_timeout != NULL) {
1560         event_release(ev_timeout);
1561         ev_timeout = NULL;
1562     }
1563
1564     /*
1565      * Now, schedule a new one if 'seconds' is greater than 0
1566      */
1567     if (seconds > 0)
1568         ev_timeout = event_register((event_id_t)seconds, EV_TIME, timeout_callback, NULL);
1569 }
1570
1571 /*
1572  * This is the callback for timeout().  If this is reached, then we
1573  * have a data timeout.
1574  */
1575 static void
1576 timeout_callback(
1577     void *      unused)
1578 {
1579     (void)unused;       /* Quiet unused parameter warning */
1580
1581     assert(unused == NULL);
1582     errstr = newstralloc(errstr, _("data timeout"));
1583     dump_result = 2;
1584     stop_dump();
1585 }
1586
1587 /*
1588  * This is called when everything needs to shut down so event_loop()
1589  * will exit.
1590  */
1591 static void
1592 stop_dump(void)
1593 {
1594     int             i;
1595     struct cmdargs *cmdargs = NULL;
1596
1597     /* Check if I have a pending ABORT command */
1598     cmdargs = get_pending_cmd();
1599     if (cmdargs) {
1600         if (cmdargs->cmd != ABORT) {
1601             error(_("beurk"));
1602         }
1603         errstr = stralloc(cmdargs->argv[1]);
1604         free_cmdargs(cmdargs);
1605     }
1606
1607     for (i = 0; i < NSTREAMS; i++) {
1608         if (streams[i].fd != NULL) {
1609             security_stream_close(streams[i].fd);
1610             streams[i].fd = NULL;
1611         }
1612     }
1613     timeout(0);
1614 }
1615
1616
1617 /*
1618  * Runs compress with the first arg as its stdout.  Returns
1619  * 0 on success or negative if error, and it's pid via the second
1620  * argument.  The outfd arg is dup2'd to the pipe to the compress
1621  * process.
1622  */
1623 static int
1624 runcompress(
1625     int         outfd,
1626     pid_t *     pid,
1627     comp_t      comptype)
1628 {
1629     int outpipe[2], rval;
1630
1631     assert(outfd >= 0);
1632     assert(pid != NULL);
1633
1634     /* outpipe[0] is pipe's stdin, outpipe[1] is stdout. */
1635     if (pipe(outpipe) < 0) {
1636         errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno));
1637         return (-1);
1638     }
1639
1640     switch (*pid = fork()) {
1641     case -1:
1642         errstr = newvstrallocf(errstr, _("couldn't fork: %s"), strerror(errno));
1643         aclose(outpipe[0]);
1644         aclose(outpipe[1]);
1645         return (-1);
1646     default:
1647         rval = dup2(outpipe[1], outfd);
1648         if (rval < 0)
1649             errstr = newvstrallocf(errstr, _("couldn't dup2: %s"), strerror(errno));
1650         aclose(outpipe[1]);
1651         aclose(outpipe[0]);
1652         return (rval);
1653     case 0:
1654         if (dup2(outpipe[0], 0) < 0) {
1655             error(_("err dup2 in: %s"), strerror(errno));
1656             /*NOTREACHED*/
1657         }
1658         if (dup2(outfd, 1) == -1) {
1659             error(_("err dup2 out: %s"), strerror(errno));
1660             /*NOTREACHED*/
1661         }
1662         if (comptype != COMP_SERVER_CUST) {
1663             char *base = stralloc(COMPRESS_PATH);
1664             log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid());
1665             amfree(base);
1666             safe_fd(-1, 0);
1667             execlp(COMPRESS_PATH, COMPRESS_PATH, (  comptype == COMP_BEST ?
1668                 COMPRESS_BEST_OPT : COMPRESS_FAST_OPT), (char *)NULL);
1669             error(_("error: couldn't exec %s: %s"), COMPRESS_PATH, strerror(errno));
1670             /*NOTREACHED*/
1671         } else if (*srvcompprog) {
1672             char *base = stralloc(srvcompprog);
1673             log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid());
1674             amfree(base);
1675             safe_fd(-1, 0);
1676             execlp(srvcompprog, srvcompprog, (char *)0);
1677             error(_("error: couldn't exec server custom filter%s.\n"), srvcompprog);
1678             /*NOTREACHED*/
1679         }
1680     }
1681     /*NOTREACHED*/
1682     return (-1);
1683 }
1684
1685 /*
1686  * Runs encrypt with the first arg as its stdout.  Returns
1687  * 0 on success or negative if error, and it's pid via the second
1688  * argument.  The outfd arg is dup2'd to the pipe to the encrypt
1689  * process.
1690  */
1691 static int
1692 runencrypt(
1693     int         outfd,
1694     pid_t *     pid,
1695     encrypt_t   encrypttype)
1696 {
1697     int outpipe[2], rval;
1698
1699     assert(outfd >= 0);
1700     assert(pid != NULL);
1701
1702     /* outpipe[0] is pipe's stdin, outpipe[1] is stdout. */
1703     if (pipe(outpipe) < 0) {
1704         errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno));
1705         return (-1);
1706     }
1707
1708     switch (*pid = fork()) {
1709     case -1:
1710         errstr = newvstrallocf(errstr, _("couldn't fork: %s"), strerror(errno));
1711         aclose(outpipe[0]);
1712         aclose(outpipe[1]);
1713         return (-1);
1714     default:
1715         rval = dup2(outpipe[1], outfd);
1716         if (rval < 0)
1717             errstr = newvstrallocf(errstr, _("couldn't dup2: %s"), strerror(errno));
1718         aclose(outpipe[1]);
1719         aclose(outpipe[0]);
1720         return (rval);
1721     case 0: {
1722         char *base;
1723         if (dup2(outpipe[0], 0) < 0) {
1724             error(_("err dup2 in: %s"), strerror(errno));
1725             /*NOTREACHED*/
1726         }
1727         if (dup2(outfd, 1) < 0 ) {
1728             error(_("err dup2 out: %s"), strerror(errno));
1729             /*NOTREACHED*/
1730         }
1731         base = stralloc(srv_encrypt);
1732         log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid());
1733         amfree(base);
1734         safe_fd(-1, 0);
1735         if ((encrypttype == ENCRYPT_SERV_CUST) && *srv_encrypt) {
1736             execlp(srv_encrypt, srv_encrypt, (char *)0);
1737             error(_("error: couldn't exec server encryption%s.\n"), srv_encrypt);
1738             /*NOTREACHED*/
1739         }
1740         }
1741     }
1742     /*NOTREACHED*/
1743     return (-1);
1744 }
1745
1746
1747 /* -------------------- */
1748
1749 static void
1750 sendbackup_response(
1751     void *              datap,
1752     pkt_t *             pkt,
1753     security_handle_t * sech)
1754 {
1755     int ports[NSTREAMS], *response_error = datap, i;
1756     char *p;
1757     char *tok;
1758     char *extra;
1759
1760     assert(response_error != NULL);
1761     assert(sech != NULL);
1762
1763     security_close_connection(sech, hostname);
1764
1765     if (pkt == NULL) {
1766         errstr = newvstrallocf(errstr, _("[request failed: %s]"),
1767             security_geterror(sech));
1768         *response_error = 1;
1769         return;
1770     }
1771
1772     extra = NULL;
1773     memset(ports, 0, SIZEOF(ports));
1774     if (pkt->type == P_NAK) {
1775 #if defined(PACKET_DEBUG)
1776         g_fprintf(stderr, _("got nak response:\n----\n%s\n----\n\n"), pkt->body);
1777 #endif
1778
1779         tok = strtok(pkt->body, " ");
1780         if (tok == NULL || strcmp(tok, "ERROR") != 0)
1781             goto bad_nak;
1782
1783         tok = strtok(NULL, "\n");
1784         if (tok != NULL) {
1785             errstr = newvstrallocf(errstr, "NAK: %s", tok);
1786             *response_error = 1;
1787         } else {
1788 bad_nak:
1789             errstr = newvstrallocf(errstr, "request NAK");
1790             *response_error = 2;
1791         }
1792         return;
1793     }
1794
1795     if (pkt->type != P_REP) {
1796         errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"),
1797             pkt_type2str(pkt->type), pkt->body);
1798         *response_error = 1;
1799         return;
1800     }
1801
1802     dbprintf(_("got response:\n----\n%s\n----\n\n"), pkt->body);
1803
1804     for(i = 0; i < NSTREAMS; i++) {
1805         ports[i] = -1;
1806         streams[i].fd = NULL;
1807     }
1808
1809     p = pkt->body;
1810     while((tok = strtok(p, " \n")) != NULL) {
1811         p = NULL;
1812
1813         /*
1814          * Error response packets have "ERROR" followed by the error message
1815          * followed by a newline.
1816          */
1817         if (strcmp(tok, "ERROR") == 0) {
1818             tok = strtok(NULL, "\n");
1819             if (tok == NULL)
1820                 tok = _("[bogus error packet]");
1821             errstr = newvstrallocf(errstr, "%s", tok);
1822             *response_error = 2;
1823             return;
1824         }
1825
1826         /*
1827          * Regular packets have CONNECT followed by three streams
1828          */
1829         if (strcmp(tok, "CONNECT") == 0) {
1830
1831             /*
1832              * Parse the three stream specifiers out of the packet.
1833              */
1834             for (i = 0; i < NSTREAMS; i++) {
1835                 tok = strtok(NULL, " ");
1836                 if (tok == NULL || strcmp(tok, streams[i].name) != 0) {
1837                     extra = vstrallocf(
1838                                 _("CONNECT token is \"%s\": expected \"%s\""),
1839                                 tok ? tok : "(null)",
1840                                 streams[i].name);
1841                     goto parse_error;
1842                 }
1843                 tok = strtok(NULL, " \n");
1844                 if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
1845                     extra = vstrallocf(
1846                         _("CONNECT %s token is \"%s\": expected a port number"),
1847                         streams[i].name, tok ? tok : "(null)");
1848                     goto parse_error;
1849                 }
1850             }
1851             continue;
1852         }
1853
1854         /*
1855          * OPTIONS [options string] '\n'
1856          */
1857         if (strcmp(tok, "OPTIONS") == 0) {
1858             tok = strtok(NULL, "\n");
1859             if (tok == NULL) {
1860                 extra = vstrallocf(_("OPTIONS token is missing"));
1861                 goto parse_error;
1862             }
1863
1864             while((p = strchr(tok, ';')) != NULL) {
1865                 char ch;
1866                 *p++ = '\0';
1867                 if(strncmp_const_skip(tok, "features=", tok, ch) == 0) {
1868                     am_release_feature_set(their_features);
1869                     if((their_features = am_string_to_feature(tok)) == NULL) {
1870                         errstr = newvstrallocf(errstr,
1871                                               _("OPTIONS: bad features value: %s"),
1872                                               tok);
1873                         goto parse_error;
1874                     }
1875                 }
1876                 tok = p;
1877             }
1878             continue;
1879         }
1880
1881         extra = vstrallocf(_("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""),
1882                           tok ? tok : "(null)");
1883         goto parse_error;
1884     }
1885
1886     if (dumper_kencrypt == KENCRYPT_WILL_DO)
1887         dumper_kencrypt = KENCRYPT_YES;
1888
1889     /*
1890      * Connect the streams to their remote ports
1891      */
1892     for (i = 0; i < NSTREAMS; i++) {
1893         if (ports[i] == -1)
1894             continue;
1895         streams[i].fd = security_stream_client(sech, ports[i]);
1896         if (streams[i].fd == NULL) {
1897             errstr = newvstrallocf(errstr,
1898                 _("[could not connect %s stream: %s]"),
1899                 streams[i].name,
1900                 security_geterror(sech));
1901             goto connect_error;
1902         }
1903     }
1904
1905     /*
1906      * Authenticate the streams
1907      */
1908     for (i = 0; i < NSTREAMS; i++) {
1909         if (streams[i].fd == NULL)
1910             continue;
1911 #ifdef KRB4_SECURITY
1912         /*
1913          * XXX krb4 historically never authenticated the index stream!
1914          * We need to reproduce this lossage here to preserve compatibility
1915          * with old clients.
1916          * It is wrong to delve into sech, but we have no choice here.
1917          */
1918         if (strcasecmp(sech->driver->name, "krb4") == 0 && i == INDEXFD)
1919             continue;
1920 #endif
1921         if (security_stream_auth(streams[i].fd) < 0) {
1922             errstr = newvstrallocf(errstr,
1923                 _("[could not authenticate %s stream: %s]"),
1924                 streams[i].name, 
1925                 security_stream_geterror(streams[i].fd));
1926             goto connect_error;
1927         }
1928     }
1929
1930     /*
1931      * The MESGFD and DATAFD streams are mandatory.  If we didn't get
1932      * them, complain.
1933      */
1934     if (streams[MESGFD].fd == NULL || streams[DATAFD].fd == NULL) {
1935         errstr = newvstrallocf(errstr, _("[couldn't open MESG or INDEX streams]"));
1936         goto connect_error;
1937     }
1938
1939     /* everything worked */
1940     *response_error = 0;
1941     return;
1942
1943 parse_error:
1944     errstr = newvstrallocf(errstr,
1945                           _("[parse of reply message failed: %s]"),
1946                           extra ? extra : _("(no additional information)"));
1947     amfree(extra);
1948     *response_error = 2;
1949     return;
1950
1951 connect_error:
1952     stop_dump();
1953     *response_error = 1;
1954 }
1955
1956 static char *
1957 dumper_get_security_conf(
1958     char *      string,
1959     void *      arg)
1960 {
1961         (void)arg;      /* Quiet unused parameter warning */
1962
1963         if(!string || !*string)
1964                 return(NULL);
1965
1966         if(strcmp(string, "krb5principal")==0) {
1967                 return(getconf_str(CNF_KRB5PRINCIPAL));
1968         } else if(strcmp(string, "krb5keytab")==0) {
1969                 return(getconf_str(CNF_KRB5KEYTAB));
1970         } else if(strcmp(string, "amandad_path")==0) {
1971                 return (amandad_path);
1972         } else if(strcmp(string, "client_username")==0) {
1973                 return (client_username);
1974         } else if(strcmp(string, "ssh_keys")==0) {
1975                 return (ssh_keys);
1976         } else if(strcmp(string, "kencrypt")==0) {
1977                 if (dumper_kencrypt == KENCRYPT_YES)
1978                     return ("yes");
1979                 else
1980                     return (NULL);
1981         }
1982         return(NULL);
1983 }
1984
1985 static int
1986 startup_dump(
1987     const char *hostname,
1988     const char *disk,
1989     const char *device,
1990     int         level,
1991     const char *dumpdate,
1992     const char *progname,
1993     const char *amandad_path,
1994     const char *client_username,
1995     const char *ssh_keys,
1996     const char *auth,
1997     const char *options)
1998 {
1999     char level_string[NUM_STR_SIZE];
2000     char *req = NULL;
2001     char *authopt;
2002     int response_error;
2003     const security_driver_t *secdrv;
2004     char *application_api;
2005     int has_features;
2006     int has_hostname;
2007     int has_device;
2008     int has_config;
2009
2010     (void)disk;                 /* Quiet unused parameter warning */
2011     (void)amandad_path;         /* Quiet unused parameter warning */
2012     (void)client_username;      /* Quiet unused parameter warning */
2013     (void)ssh_keys;             /* Quiet unused parameter warning */
2014     (void)auth;                 /* Quiet unused parameter warning */
2015
2016     has_features = am_has_feature(their_features, fe_req_options_features);
2017     has_hostname = am_has_feature(their_features, fe_req_options_hostname);
2018     has_config   = am_has_feature(their_features, fe_req_options_config);
2019     has_device   = am_has_feature(their_features, fe_sendbackup_req_device);
2020
2021     /*
2022      * Default to bsd authentication if none specified.  This is gross.
2023      *
2024      * Options really need to be pre-parsed into some sort of structure
2025      * much earlier, and then flattened out again before transmission.
2026      */
2027
2028     g_snprintf(level_string, SIZEOF(level_string), "%d", level);
2029     if(strcmp(progname, "DUMP") == 0
2030        || strcmp(progname, "GNUTAR") == 0) {
2031         application_api = "";
2032     } else {
2033         application_api = "BACKUP ";
2034     }
2035     req = vstralloc("SERVICE sendbackup\n",
2036                     "OPTIONS ",
2037                     has_features ? "features=" : "",
2038                     has_features ? our_feature_string : "",
2039                     has_features ? ";" : "",
2040                     has_hostname ? "hostname=" : "",
2041                     has_hostname ? hostname : "",
2042                     has_hostname ? ";" : "",
2043                     has_config   ? "config=" : "",
2044                     has_config   ? get_config_name() : "",
2045                     has_config   ? ";" : "",
2046                     "\n",
2047                     NULL);
2048
2049     amfree(dle_str);
2050     if (am_has_feature(their_features, fe_req_xml)) {
2051         char *o, *p = NULL;
2052         char *pclean;
2053         o = unquote_string(options+1);
2054         vstrextend(&p, "<dle>\n", NULL);
2055         if (*application_api != '\0') {
2056             vstrextend(&p, "  <program>APPLICATION</program>\n", NULL);
2057         } else {
2058             vstrextend(&p, "  <program>", progname, "</program>\n", NULL);
2059         }
2060         vstrextend(&p, "  ", b64disk, "\n", NULL);
2061         if (device && has_device) {
2062             vstrextend(&p, "  ", b64device, "\n",
2063                        NULL);
2064         }
2065         vstrextend(&p, "  <level>", level_string, "</level>\n", NULL);
2066         vstrextend(&p, o, "</dle>\n", NULL);
2067         amfree(o);
2068         pclean = clean_dle_str_for_client(p);
2069         vstrextend(&req, pclean, NULL);
2070         amfree(pclean);
2071         dle_str = p;
2072     } else if (*application_api != '\0') {
2073         errstr = newvstrallocf(errstr,
2074                 _("[does not support application-api]"));
2075         amfree(req);
2076         return 2;
2077     } else {
2078         authopt = strstr(options, "auth=");
2079         if (auth == NULL) {
2080             auth = "BSD";
2081         }
2082         vstrextend(&req,
2083                    progname,
2084                    " ", qdiskname,
2085                    " ", device && has_device ? device : "",
2086                    " ", level_string,
2087                    " ", dumpdate,
2088                    " OPTIONS ", options,
2089                    /* compat: if authopt=krb4, send krb4-auth */
2090                    (strcasecmp(authopt, "krb4") ? "" : "krb4-auth"),
2091                    "\n",
2092                    NULL);
2093     }
2094
2095     dbprintf(_("send request:\n----\n%s\n----\n\n"), req);
2096     secdrv = security_getdriver(auth);
2097     if (secdrv == NULL) {
2098         errstr = newvstrallocf(errstr,
2099                 _("[could not find security driver '%s']"), auth);
2100         amfree(req);
2101         return 2;
2102     }
2103
2104     protocol_sendreq(hostname, secdrv, dumper_get_security_conf, req,
2105         STARTUP_TIMEOUT, sendbackup_response, &response_error);
2106
2107     amfree(req);
2108
2109     protocol_run();
2110     return (response_error);
2111 }