X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=server-src%2Fdumper.c;fp=server-src%2Fdumper.c;h=32f9258780d457650c3d2f575c34f646b875a734;hb=538ae376635af705ebcd686f3b4b7b72a6652985;hp=ae04bb19a06c3449b16abbfe8693cd5450f74022;hpb=11425c69eb58b6103beb68adc13912735ba36975;p=debian%2Famanda diff --git a/server-src/dumper.c b/server-src/dumper.c index ae04bb1..32f9258 100644 --- a/server-src/dumper.c +++ b/server-src/dumper.c @@ -38,7 +38,6 @@ #include "protocol.h" #include "security.h" #include "stream.h" -#include "version.h" #include "fileheader.h" #include "amfeatures.h" #include "server_util.h" @@ -74,6 +73,16 @@ struct databuf { pid_t encryptpid; /* valid if fd is pipe to encrypt */ }; +typedef struct filter_s { + int fd; + char *name; + char *buffer; + gint64 first; /* first byte used */ + gint64 size; /* number of byte use in the buffer */ + gint64 allocated_size ; /* allocated size of the buffer */ + event_handle_t *event; +} filter_t; + static char *handle = NULL; static char *errstr = NULL; @@ -101,8 +110,11 @@ static char *options = NULL; static char *progname = NULL; static char *amandad_path=NULL; static char *client_username=NULL; +static char *client_port=NULL; static char *ssh_keys=NULL; static char *auth=NULL; +static data_path_t data_path=DATA_PATH_AMANDA; +static char *dataport_list = NULL; static int level; static char *dumpdate = NULL; static char *dumper_timestamp = NULL; @@ -110,6 +122,8 @@ static time_t conf_dtimeout; static int indexfderror; static int set_datafd; static char *dle_str = NULL; +static char *errfname = NULL; +static int errf_lines = 0; static dumpfile_t file; @@ -150,17 +164,17 @@ static void process_dumpeof(void); static void process_dumpline(const char *); static void add_msg_data(const char *, size_t); static void parse_info_line(char *); -static void log_msgout(logtype_t); +static int log_msgout(logtype_t); static char * dumper_get_security_conf (char *, void *); -static int runcompress(int, pid_t *, comp_t); +static int runcompress(int, pid_t *, comp_t, char *); static int runencrypt(int, pid_t *, encrypt_t); static void sendbackup_response(void *, pkt_t *, security_handle_t *); static int startup_dump(const char *, const char *, const char *, int, const char *, const char *, const char *, const char *, const char *, const char *, - const char *); + const char *, const char *); static void stop_dump(void); static void read_indexfd(void *, void *, ssize_t); @@ -273,25 +287,27 @@ xml_check_options( srvcompress = COMP_BEST; } else if (dle->compress == COMP_SERVER_CUST) { srvcompress = COMP_SERVER_CUST; - srvcompprog = dle->compprog; + srvcompprog = g_strdup(dle->compprog); } else if (dle->compress == COMP_CUST) { srvcompress = COMP_CUST; - clntcompprog = dle->compprog; + clntcompprog = g_strdup(dle->compprog); } else { srvcompress = COMP_NONE; } if (dle->encrypt == ENCRYPT_CUST) { srvencrypt = ENCRYPT_CUST; - clnt_encrypt = dle->clnt_encrypt; - clnt_decrypt_opt = dle->clnt_decrypt_opt; + clnt_encrypt = g_strdup(dle->clnt_encrypt); + clnt_decrypt_opt = g_strdup(dle->clnt_decrypt_opt); } else if (dle->encrypt == ENCRYPT_SERV_CUST) { srvencrypt = ENCRYPT_SERV_CUST; - srv_encrypt = dle->clnt_encrypt; - srv_decrypt_opt = dle->clnt_decrypt_opt; + srv_encrypt = g_strdup(dle->srv_encrypt); + srv_decrypt_opt = g_strdup(dle->srv_decrypt_opt); } else { srvencrypt = ENCRYPT_NONE; } + free_dle(dle); + amfree(o); } @@ -304,14 +320,19 @@ main( struct cmdargs *cmdargs = NULL; int outfd = -1; int rc; - in_port_t taper_port; + in_port_t header_port; char *q = NULL; int a; int res; - config_overwrites_t *cfg_ovr = NULL; + config_overrides_t *cfg_ovr = NULL; char *cfg_opt = NULL; int dumper_setuid; + if (argc > 1 && argv && argv[1] && g_str_equal(argv[1], "--version")) { + printf("dumper-%s\n", VERSION); + return (0); + } + /* * Configure program for internationalization: * 1) Only set the message locale for now. @@ -333,14 +354,14 @@ main( /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); - erroutput_type = (ERR_AMANDALOG|ERR_INTERACTIVE); - set_logerror(logerror); + add_amanda_log_handler(amanda_log_stderr); + add_amanda_log_handler(amanda_log_trace_log); - cfg_ovr = extract_commandline_config_overwrites(&argc, &argv); + cfg_ovr = extract_commandline_config_overrides(&argc, &argv); if (argc > 1) cfg_opt = argv[1]; + set_config_overrides(cfg_ovr); config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt); - apply_config_overwrites(cfg_ovr); if (!dumper_setuid) { error(_("dumper must be run setuid root")); @@ -352,7 +373,7 @@ main( safe_cd(); /* do this *after* config_init() */ - check_running_as(RUNNING_AS_DUMPUSER); + check_running_as(RUNNING_AS_ROOT | RUNNING_AS_UID_ONLY); dbrename(get_config_name(), DBG_SUBDIR_SERVER); @@ -363,7 +384,7 @@ main( g_fprintf(stderr, _("%s: pid %ld executable %s version %s\n"), get_pname(), (long) getpid(), - argv[0], version()); + argv[0], VERSION); fflush(stderr); /* now, make sure we are a valid user */ @@ -407,8 +428,11 @@ main( * progname * amandad_path * client_username + * client_port * ssh_keys * security_driver + * data_path + * dataport_list * options */ a = 1; /* skip "PORT-DUMP" */ @@ -423,7 +447,7 @@ main( error(_("error [dumper PORT-DUMP: not enough args: port]")); /*NOTREACHED*/ } - taper_port = (in_port_t)atoi(cmdargs->argv[a++]); + header_port = (in_port_t)atoi(cmdargs->argv[a++]); if(a >= cmdargs->argc) { error(_("error [dumper PORT-DUMP: not enough args: hostname]")); @@ -486,6 +510,11 @@ main( } client_username = newstralloc(client_username, cmdargs->argv[a++]); + if(a >= cmdargs->argc) { + error(_("error [dumper PORT-DUMP: not enough args: client_port]")); + } + client_port = newstralloc(client_port, cmdargs->argv[a++]); + if(a >= cmdargs->argc) { error(_("error [dumper PORT-DUMP: not enough args: ssh_keys]")); } @@ -496,6 +525,16 @@ main( } auth = newstralloc(auth, cmdargs->argv[a++]); + if(a >= cmdargs->argc) { + error(_("error [dumper PORT-DUMP: not enough args: data_path]")); + } + data_path = data_path_from_string(cmdargs->argv[a++]); + + if(a >= cmdargs->argc) { + error(_("error [dumper PORT-DUMP: not enough args: dataport_list]")); + } + dataport_list = newstralloc(dataport_list, cmdargs->argv[a++]); + if(a >= cmdargs->argc) { error(_("error [dumper PORT-DUMP: not enough args: options]")); } @@ -522,7 +561,8 @@ main( /* connect outf to chunker/taper port */ - outfd = stream_client("localhost", taper_port, + g_debug(_("Sending header to localhost:%d\n"), header_port); + outfd = stream_client("localhost", header_port, STREAM_BUFSIZE, 0, NULL, 0); if (outfd == -1) { @@ -538,9 +578,9 @@ main( databuf_init(&db, outfd); if (am_has_feature(their_features, fe_req_xml)) - xml_check_options(options); + xml_check_options(options); /* note: modifies globals */ else - check_options(options); + check_options(options); /* note: modifies globals */ rc = startup_dump(hostname, diskname, @@ -550,6 +590,7 @@ main( progname, amandad_path, client_username, + client_port, ssh_keys, auth, options); @@ -570,6 +611,11 @@ main( amfree(amandad_path); amfree(client_username); + amfree(client_port); + amfree(device); + amfree(b64device); + amfree(qdiskname); + amfree(b64disk); break; @@ -680,9 +726,12 @@ databuf_flush( dumpbytes %= (off_t)1024; } if (written == 0) { - m = vstrallocf(_("data write: %s"), strerror(errno)); + int save_errno = errno; + m = vstrallocf(_("data write: %s"), strerror(save_errno)); + amfree(errstr); errstr = quote_string(m); amfree(m); + errno = save_errno; return -1; } db->datain = db->dataout = db->buf; @@ -812,6 +861,11 @@ process_dumpline( break; } + if (strcmp(tok, "no-op") == 0) { + amfree(buf); + return; + } + if (strcmp(tok, "end") == 0) { SET(status, GOT_ENDLINE); break; @@ -858,6 +912,7 @@ bad_line: break; } g_fprintf(errf, "%s\n", str); + errf_lines++; amfree(buf); } @@ -945,24 +1000,33 @@ add_msg_data( } -static void +static int log_msgout( logtype_t typ) { char *line; + int count = 0; fflush(errf); - if (fseek(errf, 0L, SEEK_SET) < 0) { + if (fseeko(errf, 0L, SEEK_SET) < 0) { dbprintf(_("log_msgout: warning - seek failed: %s\n"), strerror(errno)); } while ((line = agets(errf)) != NULL) { + if (errf_lines >= 100 && count >= 20) + break; if (line[0] != '\0') { log_add(typ, "%s", line); } amfree(line); + count++; } + amfree(line); - afclose(errf); + if (errf_lines >= 100) { + log_add(typ, "Look in the '%s' file for full error messages", errfname); + } + + return errf_lines < 100; } /* ------------- */ @@ -1027,23 +1091,38 @@ finish_tapeheader( if (srvencrypt != ENCRYPT_NONE) { file->encrypted= 1; if (srvencrypt == ENCRYPT_SERV_CUST) { - g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd), - " %s %s |", srv_encrypt, srv_decrypt_opt); + if (srv_decrypt_opt) { + g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd), + " %s %s |", srv_encrypt, srv_decrypt_opt); + strncpy(file->srv_decrypt_opt, srv_decrypt_opt, SIZEOF(file->srv_decrypt_opt) - 1); + file->srv_decrypt_opt[SIZEOF(file->srv_decrypt_opt) - 1] = '\0'; + } else { + g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd), + " %s |", srv_encrypt); + file->srv_decrypt_opt[0] = '\0'; + } strncpy(file->encrypt_suffix, "enc", SIZEOF(file->encrypt_suffix) - 1); file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0'; strncpy(file->srv_encrypt, srv_encrypt, SIZEOF(file->srv_encrypt) - 1); file->srv_encrypt[SIZEOF(file->srv_encrypt) - 1] = '\0'; - strncpy(file->srv_decrypt_opt, srv_decrypt_opt, SIZEOF(file->srv_decrypt_opt) - 1); - file->srv_decrypt_opt[SIZEOF(file->srv_decrypt_opt) - 1] = '\0'; } else if ( srvencrypt == ENCRYPT_CUST ) { + if (clnt_decrypt_opt) { + g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd), + " %s %s |", clnt_encrypt, clnt_decrypt_opt); + strncpy(file->clnt_decrypt_opt, clnt_decrypt_opt, + SIZEOF(file->clnt_decrypt_opt)); + file->clnt_decrypt_opt[SIZEOF(file->clnt_decrypt_opt) - 1] = '\0'; + } else { + g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd), + " %s |", clnt_encrypt); + file->clnt_decrypt_opt[0] = '\0'; + } g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd), " %s %s |", clnt_encrypt, clnt_decrypt_opt); strncpy(file->encrypt_suffix, "enc", SIZEOF(file->encrypt_suffix) - 1); file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0'; strncpy(file->clnt_encrypt, clnt_encrypt, SIZEOF(file->clnt_encrypt) - 1); file->clnt_encrypt[SIZEOF(file->clnt_encrypt) - 1] = '\0'; - strncpy(file->clnt_decrypt_opt, clnt_decrypt_opt, SIZEOF(file->clnt_decrypt_opt)); - file->clnt_decrypt_opt[SIZEOF(file->clnt_decrypt_opt) - 1] = '\0'; } } else { if (file->encrypt_suffix[0] == '\0') { @@ -1072,7 +1151,11 @@ write_tapeheader( char * buffer; size_t written; - buffer = build_header(file, DISK_BLOCK_BYTES); + if (debug_dumper > 1) + dump_dumpfile_t(file); + buffer = build_header(file, NULL, DISK_BLOCK_BYTES); + if (!buffer) /* this shouldn't happen */ + error(_("header does not fit in %zd bytes"), (size_t)DISK_BLOCK_BYTES); written = full_write(outfd, buffer, DISK_BLOCK_BYTES); amfree(buffer); @@ -1082,6 +1165,8 @@ write_tapeheader( return -1; } +int indexout = -1; + static int do_dump( struct databuf *db) @@ -1089,14 +1174,14 @@ do_dump( char *indexfile_tmp = NULL; char *indexfile_real = NULL; char level_str[NUM_STR_SIZE]; + char *time_str; char *fn; char *q; times_t runtime; double dumptime; /* Time dump took in secs */ - char *errfname = NULL; - int indexout; pid_t indexpid = -1; char *m; + int to_unlink = 1; startclock(); @@ -1107,23 +1192,29 @@ do_dump( fh_init(&file); g_snprintf(level_str, SIZEOF(level_str), "%d", level); + time_str = get_timestamp_from_time(0); fn = sanitise_filename(diskname); + errf_lines = 0; errfname = newvstralloc(errfname, - AMANDA_TMPDIR, - "/", hostname, + AMANDA_DBGDIR, + "/log.error", NULL); + mkdir(errfname, 0700); + errfname = newvstralloc(errfname, + AMANDA_DBGDIR, + "/log.error/", hostname, ".", fn, ".", level_str, + ".", time_str, ".errout", NULL); amfree(fn); + amfree(time_str); if((errf = fopen(errfname, "w+")) == NULL) { errstr = newvstrallocf(errstr, "errfile open \"%s\": %s", errfname, strerror(errno)); amfree(errfname); goto failed; } - unlink(errfname); /* so it goes away on close */ - amfree(errfname); if (streams[INDEXFD].fd != NULL) { indexfile_real = getindexfname(hostname, diskname, dumper_timestamp, level); @@ -1144,7 +1235,7 @@ do_dump( indexfile_tmp, strerror(errno)); goto failed; } else { - if (runcompress(indexout, &indexpid, COMP_BEST) < 0) { + if (runcompress(indexout, &indexpid, COMP_BEST, "index compress") < 0) { aclose(indexout); goto failed; } @@ -1180,22 +1271,115 @@ do_dump( } dumpsize -= headersize; /* don't count the header */ - if (dumpsize <= (off_t)0) { + if (dumpsize <= (off_t)0 && data_path == DATA_PATH_AMANDA) { dumpsize = (off_t)0; dump_result = max(dump_result, 2); if (!errstr) errstr = stralloc(_("got no data")); } + if (data_path == DATA_PATH_DIRECTTCP) { + dumpsize = origsize; + } + if (!ISSET(status, HEADER_DONE)) { dump_result = max(dump_result, 2); if (!errstr) errstr = stralloc(_("got no header information")); } - if (dumpsize == 0) { + if (dumpsize == 0 && data_path == DATA_PATH_AMANDA) { dump_result = max(dump_result, 2); if (!errstr) errstr = stralloc(_("got no data")); } + if (indexfile_tmp) { + amwait_t index_status; + + /*@i@*/ aclose(indexout); + waitpid(indexpid,&index_status,0); + log_add(L_INFO, "pid-done %ld", (long)indexpid); + if (rename(indexfile_tmp, indexfile_real) != 0) { + log_add(L_WARNING, _("could not rename \"%s\" to \"%s\": %s"), + indexfile_tmp, indexfile_real, strerror(errno)); + } + amfree(indexfile_tmp); + amfree(indexfile_real); + } + + /* copy the header in a file on the index dir */ + { + FILE *a; + char *s; + char *f = getheaderfname(hostname, diskname, dumper_timestamp, level); + a = fopen(f,"w"); + if (a) { + s = build_header(&file, NULL, DISK_BLOCK_BYTES); + fprintf(a,"%s", s); + g_free(s); + fclose(a); + } + g_free(f); + } + + if (db->compresspid != -1 && dump_result < 2) { + amwait_t wait_status; + char *errmsg = NULL; + + waitpid(db->compresspid, &wait_status, 0); + if (WIFSIGNALED(wait_status)) { + errmsg = g_strdup_printf(_("%s terminated with signal %d"), + "compress", WTERMSIG(wait_status)); + } else if (WIFEXITED(wait_status)) { + if (WEXITSTATUS(wait_status) != 0) { + errmsg = g_strdup_printf(_("%s exited with status %d"), + "compress", WEXITSTATUS(wait_status)); + } + } else { + errmsg = g_strdup_printf(_("%s got bad exit"), + "compress"); + } + if (errmsg) { + g_fprintf(errf, _("? %s\n"), errmsg); + g_debug("%s", errmsg); + dump_result = max(dump_result, 2); + if (!errstr) + errstr = errmsg; + else + g_free(errmsg); + } + log_add(L_INFO, "pid-done %ld", (long)db->compresspid); + db->compresspid = -1; + } + + if (db->encryptpid != -1 && dump_result < 2) { + amwait_t wait_status; + char *errmsg = NULL; + + waitpid(db->encryptpid, &wait_status, 0); + if (WIFSIGNALED(wait_status)) { + errmsg = g_strdup_printf(_("%s terminated with signal %d"), + "encrypt", WTERMSIG(wait_status)); + } else if (WIFEXITED(wait_status)) { + if (WEXITSTATUS(wait_status) != 0) { + errmsg = g_strdup_printf(_("%s exited with status %d"), + "encrypt", WEXITSTATUS(wait_status)); + } + } else { + errmsg = g_strdup_printf(_("%s got bad exit"), + "encrypt"); + } + if (errmsg) { + g_fprintf(errf, _("? %s\n"), errmsg); + g_debug("%s", errmsg); + dump_result = max(dump_result, 2); + if (!errstr) + errstr = errmsg; + else + g_free(errmsg); + } + log_add(L_INFO, "pid-done %ld", (long)db->encryptpid); + db->encryptpid = -1; + } + if (dump_result > 1) goto failed; @@ -1213,7 +1397,7 @@ do_dump( q = quote_string(m); amfree(m); putresult(DONE, _("%s %lld %lld %lu %s\n"), handle, - (long long)origsize, + (long long)origsize, (long long)dumpsize, (unsigned long)((double)dumptime+0.5), q); amfree(q); @@ -1227,37 +1411,22 @@ do_dump( case 1: log_start_multiline(); log_add(L_STRANGE, "%s %s %d [%s]", hostname, qdiskname, level, errstr); - log_msgout(L_STRANGE); + to_unlink = log_msgout(L_STRANGE); log_end_multiline(); break; } - if (errf) afclose(errf); - - aclose(db->fd); - if (indexfile_tmp) { - amwait_t index_status; - - /*@i@*/ aclose(indexout); - waitpid(indexpid,&index_status,0); - log_add(L_INFO, "pid-done %ld", (long)indexpid); - if (rename(indexfile_tmp, indexfile_real) != 0) { - log_add(L_WARNING, _("could not rename \"%s\" to \"%s\": %s"), - indexfile_tmp, indexfile_real, strerror(errno)); - } - amfree(indexfile_tmp); - amfree(indexfile_real); + if (errf) + afclose(errf); + if (errfname) { + if (to_unlink) + unlink(errfname); + amfree(errfname); } - if(db->compresspid != -1) { - waitpid(db->compresspid,NULL,0); - log_add(L_INFO, "pid-done %ld", (long)db->compresspid); - } - if(db->encryptpid != -1) { - waitpid(db->encryptpid,NULL,0); - log_add(L_INFO, "pid-done %ld", (long)db->encryptpid); - } + if (data_path == DATA_PATH_AMANDA) + aclose(db->fd); amfree(errstr); dumpfile_free_data(&file); @@ -1325,11 +1494,17 @@ failed: log_add(L_FAIL, _("%s %s %s %d [%s]"), hostname, qdiskname, dumper_timestamp, level, errstr); if (errf) { - log_msgout(L_FAIL); + to_unlink = log_msgout(L_FAIL); } log_end_multiline(); - if (errf) afclose(errf); + if (errf) + afclose(errf); + if (errfname) { + if (to_unlink) + unlink(errfname); + amfree(errfname); + } if (indexfile_tmp) { unlink(indexfile_tmp); @@ -1337,6 +1512,9 @@ failed: amfree(indexfile_real); } + amfree(errstr); + dumpfile_free_data(&file); + return 0; } @@ -1384,6 +1562,18 @@ read_mesgfd( } if (ISSET(status, GOT_INFO_ENDLINE) && !ISSET(status, HEADER_DONE)) { + /* Use the first in the dataport_list */ + in_port_t data_port; + char *data_host = dataport_list; + char *s; + + s = strchr(dataport_list, ','); + if (s) *s = '\0'; /* use first data_port */ + s = strrchr(dataport_list, ':'); + *s = '\0'; + s++; + data_port = atoi(s); + SET(status, HEADER_DONE); /* time to do the header */ finish_tapeheader(&file); @@ -1394,6 +1584,21 @@ read_mesgfd( stop_dump(); return; } + aclose(db->fd); + if (data_path == DATA_PATH_AMANDA) { + g_debug(_("Sending data to %s:%d\n"), data_host, data_port); + db->fd = stream_client(data_host, data_port, + STREAM_BUFSIZE, 0, NULL, 0); + if (db->fd == -1) { + errstr = newvstrallocf(errstr, + _("Can't open data output stream: %s"), + strerror(errno)); + dump_result = 2; + stop_dump(); + return; + } + } + dumpsize += (off_t)DISK_BLOCK_KB; headersize += (off_t)DISK_BLOCK_KB; @@ -1409,7 +1614,7 @@ read_mesgfd( * reading the datafd. */ if ((srvcompress != COMP_NONE) && (srvcompress != COMP_CUST)) { - if (runcompress(db->fd, &db->compresspid, srvcompress) < 0) { + if (runcompress(db->fd, &db->compresspid, srvcompress, "data compress") < 0) { dump_result = 2; stop_dump(); return; @@ -1445,6 +1650,7 @@ read_datafd( errstr = newvstrallocf(errstr, _("data read: %s"), security_stream_geterror(streams[DATAFD].fd)); dump_result = 2; + aclose(db->fd); stop_dump(); return; } @@ -1462,6 +1668,7 @@ read_datafd( } security_stream_close(streams[DATAFD].fd); streams[DATAFD].fd = NULL; + aclose(db->fd); /* * If the mesg fd and index fd has also shut down, then we're done. */ @@ -1476,7 +1683,8 @@ read_datafd( */ assert(buf != NULL); if (databuf_write(db, buf, (size_t)size) < 0) { - errstr = newvstrallocf(errstr, _("data write: %s"), strerror(errno)); + int save_errno = errno; + errstr = newvstrallocf(errstr, _("data write: %s"), strerror(save_errno)); dump_result = 2; stop_dump(); return; @@ -1524,6 +1732,7 @@ read_indexfd( if ((set_datafd == 0 || streams[DATAFD].fd == NULL) && streams[MESGFD].fd == NULL) stop_dump(); + aclose(indexout); return; } @@ -1542,6 +1751,75 @@ read_indexfd( security_stream_read(streams[INDEXFD].fd, read_indexfd, cookie); } +static void +handle_filter_stderr( + void *cookie) +{ + filter_t *filter = cookie; + ssize_t nread; + char *b, *p; + gint64 len; + + event_release(filter->event); + + if (filter->buffer == NULL) { + /* allocate initial buffer */ + filter->buffer = g_malloc(2048); + filter->first = 0; + filter->size = 0; + filter->allocated_size = 2048; + } else if (filter->first > 0) { + if (filter->allocated_size - filter->size - filter->first < 1024) { + memmove(filter->buffer, filter->buffer + filter->first, + filter->size); + filter->first = 0; + } + } else if (filter->allocated_size - filter->size < 1024) { + /* double the size of the buffer */ + filter->allocated_size *= 2; + filter->buffer = g_realloc(filter->buffer, filter->allocated_size); + } + + nread = read(filter->fd, filter->buffer + filter->first + filter->size, + filter->allocated_size - filter->first - filter->size - 2); + + if (nread <= 0) { + aclose(filter->fd); + if (filter->size > 0 && filter->buffer[filter->first + filter->size - 1] != '\n') { + /* Add a '\n' at end of buffer */ + filter->buffer[filter->first + filter->size] = '\n'; + filter->size++; + } + } else { + filter->size += nread; + } + + /* process all complete lines */ + b = filter->buffer + filter->first; + filter->buffer[filter->first + filter->size] = '\0'; + while (b < filter->buffer + filter->first + filter->size && + (p = strchr(b, '\n')) != NULL) { + *p = '\0'; + g_fprintf(errf, _("? %s: %s\n"), filter->name, b); + if (errstr == NULL) { + errstr = stralloc(b); + } + len = p - b + 1; + filter->first += len; + filter->size -= len; + b = p + 1; + dump_result = max(dump_result, 1); + } + + if (nread <= 0) { + g_free(filter->buffer); + g_free(filter); + } else { + filter->event = event_register((event_id_t)filter->fd, EV_READFD, + handle_filter_stderr, filter); + } +} + /* * Startup a timeout in the event handler. If the arg is 0, * then remove the timeout. @@ -1597,8 +1875,9 @@ stop_dump(void) cmdargs = get_pending_cmd(); if (cmdargs) { if (cmdargs->cmd != ABORT) { - error(_("beurk")); + error(_("beurk %d"), cmdargs->cmd); } + amfree(errstr); errstr = stralloc(cmdargs->argv[1]); free_cmdargs(cmdargs); } @@ -1609,6 +1888,7 @@ stop_dump(void) streams[i].fd = NULL; } } + aclose(indexout); timeout(0); } @@ -1623,9 +1903,12 @@ static int runcompress( int outfd, pid_t * pid, - comp_t comptype) + comp_t comptype, + char *name) { int outpipe[2], rval; + int errpipe[2]; + filter_t *filter; assert(outfd >= 0); assert(pid != NULL); @@ -1636,11 +1919,19 @@ runcompress( return (-1); } + /* errpipe[0] is pipe's output, outpipe[1] is input. */ + if (pipe(errpipe) < 0) { + errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno)); + return (-1); + } + switch (*pid = fork()) { case -1: errstr = newvstrallocf(errstr, _("couldn't fork: %s"), strerror(errno)); aclose(outpipe[0]); aclose(outpipe[1]); + aclose(errpipe[0]); + aclose(errpipe[1]); return (-1); default: rval = dup2(outpipe[1], outfd); @@ -1648,8 +1939,20 @@ runcompress( errstr = newvstrallocf(errstr, _("couldn't dup2: %s"), strerror(errno)); aclose(outpipe[1]); aclose(outpipe[0]); + aclose(errpipe[1]); + filter = g_new0(filter_t, 1); + filter->fd = errpipe[0]; + filter->name = name; + filter->buffer = NULL; + filter->size = 0; + filter->allocated_size = 0; + filter->event = event_register((event_id_t)filter->fd, EV_READFD, + handle_filter_stderr, filter); +g_debug("event register %s %d", name, filter->fd); return (rval); case 0: + close(outpipe[1]); + close(errpipe[0]); if (dup2(outpipe[0], 0) < 0) { error(_("err dup2 in: %s"), strerror(errno)); /*NOTREACHED*/ @@ -1658,11 +1961,16 @@ runcompress( error(_("err dup2 out: %s"), strerror(errno)); /*NOTREACHED*/ } + if (dup2(errpipe[1], 2) == -1) { + error(_("err dup2 err: %s"), strerror(errno)); + /*NOTREACHED*/ + } if (comptype != COMP_SERVER_CUST) { char *base = stralloc(COMPRESS_PATH); log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid()); amfree(base); safe_fd(-1, 0); + set_root_privs(-1); execlp(COMPRESS_PATH, COMPRESS_PATH, ( comptype == COMP_BEST ? COMPRESS_BEST_OPT : COMPRESS_FAST_OPT), (char *)NULL); error(_("error: couldn't exec %s: %s"), COMPRESS_PATH, strerror(errno)); @@ -1672,8 +1980,9 @@ runcompress( log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid()); amfree(base); safe_fd(-1, 0); + set_root_privs(-1); execlp(srvcompprog, srvcompprog, (char *)0); - error(_("error: couldn't exec server custom filter%s.\n"), srvcompprog); + error(_("error: couldn't exec server custom compression '%s'.\n"), srvcompprog); /*NOTREACHED*/ } } @@ -1694,6 +2003,8 @@ runencrypt( encrypt_t encrypttype) { int outpipe[2], rval; + int errpipe[2]; + filter_t *filter; assert(outfd >= 0); assert(pid != NULL); @@ -1704,19 +2015,41 @@ runencrypt( return (-1); } + /* errpipe[0] is pipe's output, outpipe[1] is input. */ + if (pipe(errpipe) < 0) { + errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno)); + return (-1); + } + switch (*pid = fork()) { case -1: errstr = newvstrallocf(errstr, _("couldn't fork: %s"), strerror(errno)); aclose(outpipe[0]); aclose(outpipe[1]); + aclose(errpipe[0]); + aclose(errpipe[1]); return (-1); - default: + default: { + char *base; rval = dup2(outpipe[1], outfd); if (rval < 0) errstr = newvstrallocf(errstr, _("couldn't dup2: %s"), strerror(errno)); aclose(outpipe[1]); aclose(outpipe[0]); + aclose(errpipe[1]); + filter = g_new0(filter_t, 1); + filter->fd = errpipe[0]; + base = g_strdup(srv_encrypt); + filter->name = g_strdup(basename(base)); + amfree(base); + filter->buffer = NULL; + filter->size = 0; + filter->allocated_size = 0; + filter->event = event_register((event_id_t)filter->fd, EV_READFD, + handle_filter_stderr, filter); +g_debug("event register %s %d", "encrypt data", filter->fd); return (rval); + } case 0: { char *base; if (dup2(outpipe[0], 0) < 0) { @@ -1727,13 +2060,19 @@ runencrypt( error(_("err dup2 out: %s"), strerror(errno)); /*NOTREACHED*/ } + if (dup2(errpipe[1], 2) == -1) { + error(_("err dup2 err: %s"), strerror(errno)); + /*NOTREACHED*/ + } + close(errpipe[0]); base = stralloc(srv_encrypt); log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid()); amfree(base); safe_fd(-1, 0); if ((encrypttype == ENCRYPT_SERV_CUST) && *srv_encrypt) { + set_root_privs(-1); execlp(srv_encrypt, srv_encrypt, (char *)0); - error(_("error: couldn't exec server encryption%s.\n"), srv_encrypt); + error(_("error: couldn't exec server custom encryption '%s'.\n"), srv_encrypt); /*NOTREACHED*/ } } @@ -1865,6 +2204,7 @@ bad_nak: *p++ = '\0'; if(strncmp_const_skip(tok, "features=", tok, ch) == 0) { char *u = strchr(tok, ';'); + ch = ch; if (u) *u = '\0'; am_release_feature_set(their_features); @@ -1912,16 +2252,6 @@ bad_nak: for (i = 0; i < NSTREAMS; i++) { if (streams[i].fd == NULL) continue; -#ifdef KRB4_SECURITY - /* - * XXX krb4 historically never authenticated the index stream! - * We need to reproduce this lossage here to preserve compatibility - * with old clients. - * It is wrong to delve into sech, but we have no choice here. - */ - if (strcasecmp(sech->driver->name, "krb4") == 0 && i == INDEXFD) - continue; -#endif if (security_stream_auth(streams[i].fd) < 0) { errstr = newvstrallocf(errstr, _("[could not authenticate %s stream: %s]"), @@ -1975,6 +2305,8 @@ dumper_get_security_conf( return (amandad_path); } else if(strcmp(string, "client_username")==0) { return (client_username); + } else if(strcmp(string, "client_port")==0) { + return (client_port); } else if(strcmp(string, "ssh_keys")==0) { return (ssh_keys); } else if(strcmp(string, "kencrypt")==0) { @@ -1996,13 +2328,13 @@ startup_dump( const char *progname, const char *amandad_path, const char *client_username, + const char *client_port, const char *ssh_keys, const char *auth, const char *options) { char level_string[NUM_STR_SIZE]; char *req = NULL; - char *authopt; int response_error; const security_driver_t *secdrv; char *application_api; @@ -2014,6 +2346,7 @@ startup_dump( (void)disk; /* Quiet unused parameter warning */ (void)amandad_path; /* Quiet unused parameter warning */ (void)client_username; /* Quiet unused parameter warning */ + (void)client_port; /* Quiet unused parameter warning */ (void)ssh_keys; /* Quiet unused parameter warning */ (void)auth; /* Quiet unused parameter warning */ @@ -2067,7 +2400,7 @@ startup_dump( } vstrextend(&p, " ", level_string, "\n", NULL); vstrextend(&p, options+1, "\n", NULL); - pclean = clean_dle_str_for_client(p); + pclean = clean_dle_str_for_client(p, their_features); vstrextend(&req, pclean, NULL); amfree(pclean); dle_str = p; @@ -2077,7 +2410,6 @@ startup_dump( amfree(req); return 2; } else { - authopt = strstr(options, "auth="); if (auth == NULL) { auth = "BSD"; } @@ -2088,8 +2420,6 @@ startup_dump( " ", level_string, " ", dumpdate, " OPTIONS ", options, - /* compat: if authopt=krb4, send krb4-auth */ - (authopt && strcasecmp(authopt, "krb4") ? "" : "krb4-auth"), "\n", NULL); }