X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=restore-src%2Famidxtaped.c;h=54dcfa1bab4a131c67bd0d3053195fffb475b230;hb=cdbbeef9cde260e429854dd313bc0bf7560e1e24;hp=a3a27f8057a12a1c5c3b87e64d2a58b1882cf014;hpb=6663e25ecad46c729d9be4f8585c51b523ac9044;p=debian%2Famanda diff --git a/restore-src/amidxtaped.c b/restore-src/amidxtaped.c index a3a27f8..54dcfa1 100644 --- a/restore-src/amidxtaped.c +++ b/restore-src/amidxtaped.c @@ -23,7 +23,7 @@ * Authors: the Amanda Development Team. Its members are listed in a * file named AUTHORS, in the root directory of this distribution. */ -/* $Id: amidxtaped.c,v 1.58 2006/03/14 13:12:01 martinea Exp $ +/* $Id: amidxtaped.c,v 1.73 2006/07/25 19:06:46 martinea Exp $ * * This daemon extracts a dump image off a tape for amrecover and * returns it over the network. It basically, reads a number of @@ -43,35 +43,41 @@ #include "logfile.h" #include "amfeatures.h" #include "stream.h" +#include "amandad.h" #define TIMEOUT 30 static char *pgm = "amidxtaped"; /* in case argv[0] is not set */ -extern char *rst_conf_logdir; extern char *rst_conf_logfile; extern char *config_dir; static int get_lock = 0; +static int from_amandad; static am_feature_t *our_features = NULL; static am_feature_t *their_features = NULL; +static g_option_t *g_options = NULL; +static int ctlfdin, ctlfdout, datafdout; +static char *amandad_auth = NULL; -static char *get_client_line P((void)); -static char *get_client_line_fd P((int)); -static void check_security_buffer P((char*)); +static char *get_client_line(void); +static void check_security_buffer(char *); +static char *get_client_line_fd(int); /* exit routine */ -static int parent_pid = -1; -static void cleanup P((void)); +static pid_t parent_pid = -1; +static void cleanup(void); + +int main(int argc, char **argv); /* get a line from client - line terminated by \r\n */ static char * -get_client_line() +get_client_line(void) { static char *line = NULL; char *part = NULL; - int len; + size_t len; amfree(line); while(1) { @@ -92,7 +98,7 @@ get_client_line() amfree(part); dbclose(); exit(1); - /* NOTREACHED */ + /*NOTREACHED*/ } if(line) { strappend(line, part); @@ -118,18 +124,18 @@ get_client_line() /* get a line from client - line terminated by \r\n */ static char * -get_client_line_fd(fd) -int fd; +get_client_line_fd( + int fd) { static char *line = NULL; - static int line_size = 0; + static size_t line_size = 0; char *s = line; - int len = 0; + size_t len = 0; char c; - int nb; + ssize_t nb; if(line == NULL) { /* first time only, allocate initial buffer */ - s = line = malloc(128); + s = line = alloc(128); line_size = 128; } while(1) { @@ -141,7 +147,7 @@ int fd; continue; } dbprintf(("%s: Control pipe read error - %s\n", - pgm, strerror(errno))); + pgm, strerror(errno))); break; } @@ -150,7 +156,7 @@ int fd; line = realloc(line, line_size); if (line == NULL) { error("Memory reallocation failure"); - /* NOTREACHED */ + /*NOTREACHED*/ } s = &line[len]; } @@ -171,48 +177,61 @@ int fd; } -void check_security_buffer(buffer) - char *buffer; +void +check_security_buffer( + char * buffer) { socklen_t i; struct sockaddr_in addr; char *s, *fp, ch; char *errstr = NULL; - - i = sizeof (addr); - if (getpeername(0, (struct sockaddr *)&addr, &i) == -1) - error("getpeername: %s", strerror(errno)); - if (addr.sin_family != AF_INET || ntohs(addr.sin_port) == 20) { - error("connection rejected from %s family %d port %d", + + dbprintf(("%s: check_security_buffer(buffer='%s')\n", + debug_prefix(NULL), buffer)); + + i = SIZEOF(addr); + if (getpeername(0, (struct sockaddr *)&addr, &i) == -1) { + error("getpeername: %s", strerror(errno)); + /*NOTREACHED*/ + } + if ((addr.sin_family != (sa_family_t)AF_INET) + || (ntohs(addr.sin_port) == 20)) { + error("connection rejected from %s family %d port %d", inet_ntoa(addr.sin_addr), addr.sin_family, htons(addr.sin_port)); - } - - /* do the security thing */ - s = buffer; - ch = *s++; - - skip_whitespace(s, ch); - if (ch == '\0') { - error("cannot parse SECURITY line"); - } - fp = s-1; - skip_non_whitespace(s, ch); - s[-1] = '\0'; - if (strcmp(fp, "SECURITY") != 0) { - error("cannot parse SECURITY line"); - } - skip_whitespace(s, ch); - if (!check_security(&addr, s-1, 0, &errstr)) { - error("security check failed: %s", errstr); - } + /*NOTREACHED*/ + } + + /* do the security thing */ + s = buffer; + ch = *s++; + + skip_whitespace(s, ch); + if (ch == '\0') { + error("cannot parse SECURITY line"); + /*NOTREACHED*/ + } + fp = s-1; + skip_non_whitespace(s, ch); + s[-1] = '\0'; + if (strcmp(fp, "SECURITY") != 0) { + error("cannot parse SECURITY line"); + /*NOTREACHED*/ + } + skip_whitespace(s, ch); + if (!check_security(&addr, s-1, 0, &errstr)) { + error("security check failed: %s", errstr); + /*NOTREACHED*/ + } } -int main(argc, argv) -int argc; -char **argv; +int +main( + int argc, + char ** argv) { char *buf = NULL; - int data_sock = -1, data_port = -1; + int data_sock = -1; + in_port_t data_port = (in_port_t)-1; socklen_t socklen; struct sockaddr_in addr; match_list_t *match_list; @@ -221,12 +240,13 @@ char **argv; rst_flags_t *rst_flags; int use_changer = 0; FILE *prompt_stream = NULL; - int re_end = 0; + int re_end; char *re_config = NULL; char *conf_tapetype; tapetype_t *tape; + char *line; - safe_fd(-1, 0); + safe_fd(DATA_FD_OFFSET, 4); safe_cd(); /* Don't die when child closes pipe */ @@ -254,6 +274,16 @@ char **argv; set_pname(pgm); + if(argv && argv[1] && strcmp(argv[1], "amandad") == 0) { + from_amandad = 1; + if(argv[2]) + amandad_auth = argv[2]; + } + else { + from_amandad = 0; + safe_fd(-1, 0); + } + #ifdef FORCE_USERID /* we'd rather not run as root */ @@ -261,9 +291,12 @@ char **argv; if(geteuid() == 0) { if(client_uid == (uid_t) -1) { error("error [cannot find user %s in passwd file]\n", CLIENT_LOGIN); + /*NOTREACHED*/ } + /*@ignore@*/ initgroups(CLIENT_LOGIN, client_gid); + /*@end@*/ setgid(client_gid); setuid(client_uid); } @@ -275,7 +308,7 @@ char **argv; chats to stderr, which we don't want going to client */ /* if no debug file, ship to bit bucket */ (void)close(STDERR_FILENO); - dbopen(); + dbopen(DBG_SUBDIR_SERVER); startclock(); dbprintf(("%s: version %s\n", pgm, version())); #ifdef DEBUG_CODE @@ -304,35 +337,83 @@ char **argv; debug_prefix_time(NULL))); } - socklen = sizeof (addr); - if (getpeername(0, (struct sockaddr *)&addr, &socklen) == -1) - error("getpeername: %s", strerror(errno)); - if (addr.sin_family != AF_INET || ntohs(addr.sin_port) == 20) { - error("connection rejected from %s family %d port %d", - inet_ntoa(addr.sin_addr), addr.sin_family, htons(addr.sin_port)); - } + if(from_amandad == 0) { + socklen = SIZEOF(addr); + if (getpeername(0, (struct sockaddr *)&addr, &socklen) == -1) { + error("getpeername: %s", strerror(errno)); + /*NOTREACHED*/ + } + if ((addr.sin_family != (sa_family_t)AF_INET) + || (ntohs(addr.sin_port) == 20)) { + error("connection rejected from %s family %d port %d", + inet_ntoa(addr.sin_addr), addr.sin_family, + htons(addr.sin_port)); + /*NOTREACHED*/ + } - /* do the security thing */ - amfree(buf); - buf = stralloc(get_client_line()); - check_security_buffer(buf); + /* do the security thing */ + amfree(buf); + buf = stralloc(get_client_line()); + check_security_buffer(buf); + } + else { + ctlfdout = DATA_FD_OFFSET + 0; + ctlfdin = DATA_FD_OFFSET + 1; + datafdout = DATA_FD_OFFSET + 2; + close(DATA_FD_OFFSET +3); + + /* read the REQ packet */ + for(; (line = agets(stdin)) != NULL; free(line)) { +#define sc "OPTIONS " + if(strncmp(line, sc, sizeof(sc)-1) == 0) { +#undef sc + g_options = parse_g_options(line+8, 1); + if(!g_options->hostname) { + g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1); + gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH); + g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0'; + } + } + } + amfree(line); + + if(amandad_auth && g_options->auth) { + if(strcasecmp(amandad_auth, g_options->auth) != 0) { + printf("ERROR recover program ask for auth=%s while amidxtaped is configured for '%s'\n", + g_options->auth, amandad_auth); + error("ERROR recover program ask for auth=%s while amidxtaped is configured for '%s'", + g_options->auth, amandad_auth); + /*NOTREACHED*/ + } + } + /* send the REP packet */ + printf("CONNECT CTL %d DATA %d\n", DATA_FD_OFFSET, DATA_FD_OFFSET+1); + printf("\n"); + fflush(stdout); + fflush(stdin); + if ((dup2(ctlfdout, fileno(stdout)) < 0) + || (dup2(ctlfdin, fileno(stdin)) < 0)) { + error("amandad: Failed to setup stdin or stdout"); + /*NOTREACHED*/ + } + } /* get the number of arguments */ - match_list = alloc(sizeof(match_list_t)); + match_list = alloc(SIZEOF(match_list_t)); match_list->next = NULL; match_list->hostname = ""; match_list->datestamp = ""; match_list->level = ""; match_list->diskname = ""; - do { + for (re_end = 0; re_end == 0; ) { amfree(buf); buf = stralloc(get_client_line()); if(strncmp(buf, "LABEL=", 6) == 0) { tapes = unmarshal_tapelist_str(buf+6); } else if(strncmp(buf, "FSF=", 4) == 0) { - rst_flags->fsf = atoi(buf + 4); + rst_flags->fsf = OFF_T_ATOI(buf + 4); } else if(strncmp(buf, "HEADER", 6) == 0) { rst_flags->headers = 1; @@ -344,7 +425,10 @@ char **argv; their_features = am_string_to_feature(their_feature_string); amfree(their_feature_string); our_feature_string = am_feature_to_string(our_features); - printf("%s", our_feature_string); + if(from_amandad == 1) + printf("FEATURES=%s\r\n", our_feature_string); + else + printf("%s", our_feature_string); fflush(stdout); amfree(our_feature_string); } @@ -370,9 +454,7 @@ char **argv; /* XXX does nothing? amrestore_nargs = atoi(buf); */ re_end = 1; } - else { - } - } while (re_end == 0); + } amfree(buf); if(!tapes && rst_flags->alt_tapedev){ @@ -394,9 +476,11 @@ char **argv; re_config = NULL; } amfree(conffile); + + dbrename(config_name, DBG_SUBDIR_SERVER); } - if(tapes && + if(tapes && (!rst_flags->alt_tapedev || (re_config && ( strcmp(rst_flags->alt_tapedev, getconf_str(CNF_AMRECOVER_CHANGER)) == 0 || @@ -405,7 +489,7 @@ char **argv; /* We need certain options, if restoring from more than one tape */ if(tapes->next && !am_has_feature(their_features, fe_recover_splits)) { error("%s: Client must support split dumps to restore requested data.", get_pname()); - /* NOTREACHED */ + /*NOTREACHED*/ } dbprintf(("%s: Restoring from changer, checking labels\n", get_pname())); rst_flags->check_labels = 1; @@ -413,7 +497,7 @@ char **argv; } /* If we'll be stepping on the tape server's devices, lock them. */ - if(re_config && + if(re_config && (use_changer || (rst_flags->alt_tapedev && strcmp(rst_flags->alt_tapedev, getconf_str(CNF_TAPEDEV)) == 0) ) ) { @@ -431,45 +515,56 @@ char **argv; /* Read the default block size from the tape type */ if(re_config && (conf_tapetype = getconf_str(CNF_TAPETYPE)) != NULL) { tape = lookup_tapetype(conf_tapetype); - rst_flags->blocksize = tape->blocksize * 1024; + rst_flags->blocksize = tapetype_get_blocksize(tape) * 1024; } - if(rst_flags->fsf && re_config && - getconf_int(CNF_AMRECOVER_DO_FSF) == 0) { - rst_flags->fsf = 0; + if(rst_flags->fsf && re_config && + getconf_boolean(CNF_AMRECOVER_DO_FSF) == 0) { + rst_flags->fsf = (off_t)0; } - if(re_config && getconf_int(CNF_AMRECOVER_CHECK_LABEL) == 0) { + if (!use_changer && re_config && + getconf_boolean(CNF_AMRECOVER_CHECK_LABEL) == 0) { rst_flags->check_labels = 0; } /* establish a distinct data connection for dumpfile data */ - if(am_has_feature(their_features, fe_recover_splits)){ - int data_fd; - char *buf; - - dbprintf(("%s: Client understands split dumpfiles\n", get_pname())); - - if((data_sock = stream_server(&data_port, STREAM_BUFSIZE, -1)) < 0){ - error("%s: could not create data socket: %s", get_pname(), - strerror(errno)); - } - dbprintf(("%s: Local port %d set aside for data\n", get_pname(), - data_port)); - - printf("CONNECT %d\n", data_port); /* tell client where to connect */ - fflush(stdout); - - if((data_fd = stream_accept(data_sock, TIMEOUT, -1, -1)) < 0){ - error("stream_accept failed for client data connection: %s\n", - strerror(errno)); + if(am_has_feature(their_features, fe_recover_splits)) { + if(from_amandad == 1) { + rst_flags->pipe_to_fd = datafdout; + prompt_stream = stdout; } + else { + int data_fd; + char *buf; - buf = get_client_line_fd(data_fd); + dbprintf(("%s: Client understands split dumpfiles\n",get_pname())); - check_security_buffer(buf); - rst_flags->pipe_to_fd = data_fd; - prompt_stream = stdout; + if((data_sock = stream_server(&data_port, STREAM_BUFSIZE, + STREAM_BUFSIZE, 0)) < 0){ + error("%s: could not create data socket: %s", get_pname(), + strerror(errno)); + /*NOTREACHED*/ + } + dbprintf(("%s: Local port %d set aside for data\n", get_pname(), data_port)); + + /* tell client where to connect */ + printf("CONNECT %hu\n", (unsigned short)data_port); + fflush(stdout); + + if((data_fd = stream_accept(data_sock, TIMEOUT, STREAM_BUFSIZE, + STREAM_BUFSIZE)) < 0){ + error("stream_accept failed for client data connection: %s\n", + strerror(errno)); + /*NOTREACHED*/ + } + + buf = get_client_line_fd(data_fd); + + check_security_buffer(buf); + rst_flags->pipe_to_fd = data_fd; + prompt_stream = stdout; + } } else { rst_flags->pipe_to_fd = fileno(stdout); @@ -477,23 +572,40 @@ char **argv; } dbprintf(("%s: Sending output to file descriptor %d\n", get_pname(), rst_flags->pipe_to_fd)); - - + + + if(get_lock == 0 && + re_config && + (use_changer || (rst_flags->alt_tapedev && + strcmp(rst_flags->alt_tapedev, + getconf_str(CNF_TAPEDEV)) == 0) ) ) { + send_message(prompt_stream, rst_flags, their_features, + "%s exists: amdump or amflush is already running, " + "or you must run amcleanup", + rst_conf_logfile); + error("%s exists: amdump or amflush is already running, " + "or you must run amcleanup", + rst_conf_logfile); + } + /* make sure our restore flags aren't crazy */ - if(check_rst_flags(rst_flags) == -1){ - if(rst_flags->pipe_to_fd != -1) aclose(rst_flags->pipe_to_fd); + if (check_rst_flags(rst_flags) == -1) { + if (rst_flags->pipe_to_fd != -1) + aclose(rst_flags->pipe_to_fd); + send_message(prompt_stream, rst_flags, their_features, + "restore flags are crazy"); exit(1); } - + /* actual restoration */ search_tapes(prompt_stream, use_changer, tapes, match_list, rst_flags, their_features); dbprintf(("%s: Restoration finished\n", debug_prefix_time(NULL))); - + /* cleanup */ if(rst_flags->pipe_to_fd != -1) aclose(rst_flags->pipe_to_fd); free_tapelist(tapes); - + am_release_feature_set(their_features); amfree(rst_flags->alt_tapedev); @@ -515,4 +627,3 @@ cleanup(void) if(get_lock) unlink(rst_conf_logfile); } } -