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