X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=server-src%2Famcheck.c;h=9e83962ea1ba19cdf84a5241a592870213b6a933;hb=12179dea039515c06168c0037d048566a3f623de;hp=f7fb4fcfc545a790202bf0b9083b18528353cb9d;hpb=3ab887b9bc819a846c75dd7f2ee5d41fac22b19f;p=debian%2Famanda diff --git a/server-src/amcheck.c b/server-src/amcheck.c index f7fb4fc..9e83962 100644 --- a/server-src/amcheck.c +++ b/server-src/amcheck.c @@ -24,65 +24,52 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: amcheck.c,v 1.50.2.19.2.7.2.22 2004/03/16 19:03:39 martinea Exp $ + * $Id: amcheck.c,v 1.149 2006/08/24 01:57:16 paddy_s Exp $ * * checks for common problems in server and clients */ #include "amanda.h" +#include "util.h" #include "conffile.h" #include "statfs.h" #include "diskfile.h" #include "tapefile.h" #include "tapeio.h" #include "changer.h" +#include "packet.h" +#include "security.h" #include "protocol.h" #include "clock.h" #include "version.h" #include "amindex.h" #include "token.h" -#include "util.h" +#include "taperscan.h" +#include "server_util.h" #include "pipespawn.h" #include "amfeatures.h" -/* - * If we don't have the new-style wait access functions, use our own, - * compatible with old-style BSD systems at least. Note that we don't - * care about the case w_stopval == WSTOPPED since we don't ask to see - * stopped processes, so should never get them from wait. - */ -#ifndef WEXITSTATUS -# define WEXITSTATUS(r) (((union wait *) &(r))->w_retcode) -# define WTERMSIG(r) (((union wait *) &(r))->w_termsig) - -# undef WIFSIGNALED -# define WIFSIGNALED(r) (((union wait *) &(r))->w_termsig != 0) -#endif - #define BUFFER_SIZE 32768 -static int conf_ctimeout; +static time_t conf_ctimeout; static int overwrite; -dgram_t *msg = NULL; -static disklist_t *origqp; +static disklist_t origq; static uid_t uid_dumpuser; /* local functions */ -void usage P((void)); -int start_client_checks P((int fd)); -int start_server_check P((int fd, int do_localchk, int do_tapechk)); -int main P((int argc, char **argv)); -int scan_init P((int rc, int ns, int bk)); -int taperscan_slot P((int rc, char *slotstr, char *device)); -char *taper_scan P((void)); -int test_server_pgm P((FILE *outf, char *dir, char *pgm, - int suid, uid_t dumpuid)); - -void usage() +void usage(void); +pid_t start_client_checks(int fd); +pid_t start_server_check(int fd, int do_localchk, int do_tapechk); +int main(int argc, char **argv); +int test_server_pgm(FILE *outf, char *dir, char *pgm, int suid, uid_t dumpuid); + +void +usage(void) { - error("Usage: amcheck%s [-M ] [-mawsclt] [host [disk]* ]*", versionsuffix()); + error("Usage: amcheck%s [-am] [-w] [-sclt] [-M
] [host [disk]* ]* [-o configoption]*", versionsuffix()); + /*NOTREACHED*/ } static unsigned long malloc_hist_1, malloc_size_1; @@ -90,24 +77,26 @@ static unsigned long malloc_hist_2, malloc_size_2; static am_feature_t *our_features = NULL; static char *our_feature_string = NULL; +static char *displayunit; +static long int unitdivisor; -int main(argc, argv) -int argc; -char **argv; +int +main( + int argc, + char ** argv) { char buffer[BUFFER_SIZE]; char *version_string; char *mainfname = NULL; char pid_str[NUM_STR_SIZE]; - int do_clientchk, clientchk_pid, client_probs; - int do_localchk, do_tapechk, serverchk_pid, server_probs; - int chk_flag; - int opt, size, result_port, tempfd, mainfd; + int do_clientchk, client_probs; + int do_localchk, do_tapechk, server_probs; + pid_t clientchk_pid, serverchk_pid; + int opt, tempfd, mainfd; + ssize_t size; amwait_t retstat; pid_t pid; extern int optind; - int l, n, s; - int fd; char *mailto = NULL; extern char *optarg; int mailout; @@ -118,56 +107,54 @@ char **argv; char *dumpuser; struct passwd *pw; uid_t uid_me; + int new_argc, my_argc; + char **new_argv, **my_argv; + char *errstr; - for(fd = 3; fd < FD_SETSIZE; fd++) { - /* - * Make sure nobody spoofs us with a lot of extra open files - * that would cause an open we do to get a very high file - * descriptor, which in turn might be used as an index into - * an array (e.g. an fd_set). - */ - close(fd); - } - + safe_fd(-1, 0); safe_cd(); set_pname("amcheck"); - dbopen(); + /* Don't die when child closes pipe */ + signal(SIGPIPE, SIG_IGN); + + dbopen(DBG_SUBDIR_SERVER); + + memset(buffer, 0, sizeof(buffer)); malloc_size_1 = malloc_inuse(&malloc_hist_1); - ap_snprintf(pid_str, sizeof(pid_str), "%ld", (long)getpid()); + snprintf(pid_str, SIZEOF(pid_str), "%ld", (long)getpid()); erroutput_type = ERR_INTERACTIVE; our_features = am_init_feature_set(); our_feature_string = am_feature_to_string(our_features); - /* set up dgram port first thing */ - - msg = dgram_alloc(); - - if(dgram_bind(msg, &result_port) == -1) - error("could not bind result datagram port: %s", strerror(errno)); - if(geteuid() == 0) { - /* set both real and effective uid's to real uid, likewise for gid */ - setgid(getgid()); - setuid(getuid()); + seteuid(getuid()); } uid_me = getuid(); alwaysmail = mailout = overwrite = 0; do_localchk = do_tapechk = do_clientchk = 0; - chk_flag = 0; server_probs = client_probs = 0; tempfd = mainfd = -1; + parse_server_conf(argc, argv, &new_argc, &new_argv); + my_argc = new_argc; + my_argv = new_argv; + /* process arguments */ - while((opt = getopt(argc, argv, "M:mawsclt")) != EOF) { + while((opt = getopt(my_argc, my_argv, "M:mawsclt")) != EOF) { switch(opt) { case 'M': mailto=stralloc(optarg); + if(!validate_mailto(mailto)){ + printf("Invalid characters in mail address\n"); + exit(1); + } + /*FALLTHROUGH*/ case 'm': #ifdef MAILER mailout = 1; @@ -187,52 +174,93 @@ char **argv; exit(1); #endif break; - case 's': do_localchk = 1; do_tapechk = 1; - chk_flag = 1; + case 's': do_localchk = do_clientchk = do_tapechk = 1; break; case 'c': do_clientchk = 1; - chk_flag = 1; break; case 'l': do_localchk = 1; - chk_flag = 1; break; - case 'w': do_tapechk = 1; overwrite = 1; - chk_flag = 1; + case 'w': overwrite = 1; break; case 't': do_tapechk = 1; - chk_flag = 1; break; case '?': default: usage(); } } - argc -= optind, argv += optind; - if(! chk_flag) { + my_argc -= optind, my_argv += optind; + if(my_argc < 1) usage(); + + + if ((do_localchk | do_clientchk | do_tapechk) == 0) { + /* Check everything if individual checks were not asked for */ do_localchk = do_clientchk = do_tapechk = 1; } - if(argc < 1) usage(); + if(overwrite) + do_tapechk = 1; - config_name = stralloc(*argv); + config_name = stralloc(*my_argv); config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL); conffile = stralloc2(config_dir, CONFFILE_NAME); if(read_conffile(conffile)) { error("errors processing config file \"%s\"", conffile); + /*NOTREACHED*/ } + + dbrename(config_name, DBG_SUBDIR_SERVER); + + report_bad_conf_arg(); + amfree(conffile); - conf_ctimeout = getconf_int(CNF_CTIMEOUT); + if(mailout && !mailto && + (getconf_seen(CNF_MAILTO)==0 || strlen(getconf_str(CNF_MAILTO)) == 0)) { + printf("\nNo mail address configured in amanda.conf\n"); + if(alwaysmail) + printf("When using -a option please specify -Maddress also\n\n"); + else + printf("Use -Maddress instead of -m\n\n"); + exit(1); + } + if(mailout && !mailto) + { + if(getconf_seen(CNF_MAILTO) && + strlen(getconf_str(CNF_MAILTO)) > 0) { + if(!validate_mailto(getconf_str(CNF_MAILTO))){ + printf("\nMail address in amanda.conf has invalid characters"); + printf("\nNo email will be sent\n"); + mailout = 0; + } + } + else { + printf("\nNo mail address configured in amanda.conf\n"); + if(alwaysmail) + printf("When using -a option please specify -Maddress also\n\n"); + else + printf("Use -Maddress instead of -m\n\n"); + exit(1); + } + } + + conf_ctimeout = getconf_time(CNF_CTIMEOUT); + conf_diskfile = getconf_str(CNF_DISKFILE); if (*conf_diskfile == '/') { conf_diskfile = stralloc(conf_diskfile); } else { conf_diskfile = stralloc2(config_dir, conf_diskfile); } - if((origqp = read_diskfile(conf_diskfile)) == NULL) { + if(read_diskfile(conf_diskfile, &origq) < 0) { error("could not load disklist %s", conf_diskfile); + /*NOTREACHED*/ + } + errstr = match_disklist(&origq, my_argc-1, my_argv+1); + if (errstr) { + printf("%s",errstr); + amfree(errstr); } - match_disklist(origqp, argc-1, argv+1); amfree(conf_diskfile); /* @@ -241,17 +269,22 @@ char **argv; dumpuser = getconf_str(CNF_DUMPUSER); if ((pw = getpwnam(dumpuser)) == NULL) { error("cannot look up dump user \"%s\"", dumpuser); + /*NOTREACHED*/ } uid_dumpuser = pw->pw_uid; if ((pw = getpwuid(uid_me)) == NULL) { error("cannot look up my own uid (%ld)", (long)uid_me); + /*NOTREACHED*/ } if (uid_me != uid_dumpuser) { error("running as user \"%s\" instead of \"%s\"", - pw->pw_name, - dumpuser); + pw->pw_name, dumpuser); + /*NOTREACHED*/ } + displayunit = getconf_str(CNF_DISPLAYUNIT); + unitdivisor = getconf_unit_divisor(); + /* * If both server and client side checks are being done, the server * check output goes to the main output, while the client check output @@ -263,8 +296,10 @@ char **argv; if(do_clientchk && (do_localchk || do_tapechk)) { /* we need the temp file */ tempfname = vstralloc(AMANDA_TMPDIR, "/amcheck.temp.", pid_str, NULL); - if((tempfd = open(tempfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) + if((tempfd = open(tempfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) { error("could not open %s: %s", tempfname, strerror(errno)); + /*NOTREACHED*/ + } unlink(tempfname); /* so it goes away on close */ amfree(tempfname); } @@ -272,8 +307,10 @@ char **argv; if(mailout) { /* the main fd is a file too */ mainfname = vstralloc(AMANDA_TMPDIR, "/amcheck.main.", pid_str, NULL); - if((mainfd = open(mainfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) + if((mainfd = open(mainfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) { error("could not open %s: %s", mainfname, strerror(errno)); + /*NOTREACHED*/ + } unlink(mainfname); /* so it goes away on close */ amfree(mainfname); } @@ -283,11 +320,10 @@ char **argv; /* start server side checks */ - if(do_localchk || do_tapechk) { + if(do_localchk || do_tapechk) serverchk_pid = start_server_check(mainfd, do_localchk, do_tapechk); - } else { + else serverchk_pid = 0; - } /* start client side checks */ @@ -313,44 +349,44 @@ char **argv; char number[NUM_STR_SIZE]; char *wait_msg = NULL; - ap_snprintf(number, sizeof(number), "%ld", (long)pid); + snprintf(number, SIZEOF(number), "%ld", (long)pid); wait_msg = vstralloc("parent: reaped bogus pid ", number, "\n", NULL); - for(l = 0, n = strlen(wait_msg); l < n; l += s) { - if((s = write(mainfd, wait_msg + l, n - l)) < 0) { - error("write main file: %s", strerror(errno)); - } + if (fullwrite(mainfd, wait_msg, strlen(wait_msg)) < 0) { + error("write main file: %s", strerror(errno)); + /*NOTREACHED*/ } amfree(wait_msg); } } - amfree(msg); /* copy temp output to main output and write tagline */ if(do_clientchk && (do_localchk || do_tapechk)) { - if(lseek(tempfd, 0, 0) == -1) + if(lseek(tempfd, (off_t)0, 0) == (off_t)-1) { error("seek temp file: %s", strerror(errno)); + /*NOTREACHED*/ + } - while((size=read(tempfd, buffer, sizeof(buffer))) > 0) { - for(l = 0; l < size; l += s) { - if((s = write(mainfd, buffer + l, size - l)) < 0) { - error("write main file: %s", strerror(errno)); - } + while((size = fullread(tempfd, buffer, SIZEOF(buffer))) > 0) { + if (fullwrite(mainfd, buffer, (size_t)size) < 0) { + error("write main file: %s", strerror(errno)); + /*NOTREACHED*/ } } - if(size < 0) + if(size < 0) { error("read temp file: %s", strerror(errno)); + /*NOTREACHED*/ + } aclose(tempfd); } version_string = vstralloc("\n", "(brought to you by Amanda ", version(), ")\n", NULL); - for(l = 0, n = strlen(version_string); l < n; l += s) { - if((s = write(mainfd, version_string + l, n - l)) < 0) { - error("write main file: %s", strerror(errno)); - } + if (fullwrite(mainfd, version_string, strlen(version_string)) < 0) { + error("write main file: %s", strerror(errno)); + /*NOTREACHED*/ } amfree(version_string); amfree(config_dir); @@ -378,10 +414,8 @@ char **argv; char *subject; char **a; amwait_t retstat; - pid_t mailpid; - pid_t wpid; - int r; - int w; + ssize_t r; + ssize_t w; char *err = NULL; char *extra_info = NULL; char *line = NULL; @@ -391,8 +425,9 @@ char **argv; char number[NUM_STR_SIZE]; fflush(stdout); - if(lseek(mainfd, (off_t)0, SEEK_SET) == -1) { + if(lseek(mainfd, (off_t)0, SEEK_SET) == (off_t)-1) { error("lseek main file: %s", strerror(errno)); + /*NOTREACHED*/ } if(alwaysmail && !(server_probs || client_probs)) { subject = stralloc2(getconf_str(CNF_ORG), @@ -409,19 +444,20 @@ char **argv; * Remember that split() returns the original input string in * argv[0], so we have to skip over that. */ - a = (char **) alloc((MAILTO_LIMIT + 1) * sizeof(char *)); - memset(a, 0, (MAILTO_LIMIT + 1) * sizeof(char *)); + a = (char **) alloc((MAILTO_LIMIT + 1) * SIZEOF(char *)); + memset(a, 0, (MAILTO_LIMIT + 1) * SIZEOF(char *)); if(mailto) { a[1] = mailto; a[2] = NULL; } else { - n = split(getconf_str(CNF_MAILTO), a, MAILTO_LIMIT, " "); - a[n + 1] = NULL; + r = (ssize_t)split(getconf_str(CNF_MAILTO), a, MAILTO_LIMIT, " "); + a[r + 1] = NULL; } if((nullfd = open("/dev/null", O_RDWR)) < 0) { error("nullfd: /dev/null: %s", strerror(errno)); + /*NOTREACHED*/ } - mailpid = pipespawn(MAILER, STDIN_PIPE | STDERR_PIPE, + pipespawn(MAILER, STDIN_PIPE | STDERR_PIPE, &mailfd, &nullfd, &errfd, MAILER, "-s", subject, @@ -436,28 +472,36 @@ char **argv; * cases, the pipe will break and we will exit out of the loop. */ signal(SIGPIPE, SIG_IGN); - while((r = fullread(mainfd, buffer, sizeof(buffer))) > 0) { - if((w = fullwrite(mailfd, buffer, r)) != r) { + while((r = fullread(mainfd, buffer, SIZEOF(buffer))) > 0) { + if((w = fullwrite(mailfd, buffer, (size_t)r)) != (ssize_t)r) { if(w < 0 && errno == EPIPE) { strappend(extra_info, "EPIPE writing to mail process\n"); break; } else if(w < 0) { error("mailfd write: %s", strerror(errno)); + /*NOTREACHED*/ } else { error("mailfd write: wrote %d instead of %d", w, r); + /*NOTREACHED*/ } } } aclose(mailfd); ferr = fdopen(errfd, "r"); + if (!ferr) { + error("Can't fdopen: %s", strerror(errno)); + /*NOTREACHED*/ + } for(; (line = agets(ferr)) != NULL; free(line)) { + if (line[0] == '\0') + continue; strappend(extra_info, line); strappend(extra_info, "\n"); } afclose(ferr); errfd = -1; rc = 0; - while ((wpid = wait(&retstat)) != -1) { + while (wait(&retstat) != -1) { if (WIFSIGNALED(retstat)) { ret = 0; rc = sig = WTERMSIG(retstat); @@ -472,7 +516,7 @@ char **argv; } else { strappend(err, "returned "); } - ap_snprintf(number, sizeof(number), "%d", ret); + snprintf(number, SIZEOF(number), "%d", ret); strappend(err, number); } } @@ -482,9 +526,13 @@ char **argv; amfree(extra_info); } error("error running mailer %s: %s", MAILER, err); + /*NOTREACHED*/ } } #endif + free_new_argv(new_argc, new_argv); + free_server_config(); + dbclose(); return (server_probs || client_probs); } @@ -497,178 +545,71 @@ char *first_match_label = NULL, *first_match = NULL, *found_device = NULL; char *label; char *searchlabel, *labelstr; tape_t *tp; -FILE *errf; - -int scan_init(rc, ns, bk) -int rc, ns, bk; -{ - if(rc) - error("could not get changer info: %s", changer_resultstr); - - nslots = ns; - backwards = bk; - - return 0; -} - -int taperscan_slot(rc, slotstr, device) -int rc; -char *slotstr; -char *device; -{ - char *errstr; - - if(rc == 2) { - fprintf(errf, "%s: fatal slot %s: %s\n", - get_pname(), slotstr, changer_resultstr); - return 1; - } - else if(rc == 1) { - fprintf(errf, "%s: slot %s: %s\n", - get_pname(), slotstr, changer_resultstr); - return 0; - } - else { - if((errstr = tape_rdlabel(device, &datestamp, &label)) != NULL) { - fprintf(errf, "%s: slot %s: %s\n", get_pname(), slotstr, errstr); - } else { - /* got an amanda tape */ - fprintf(errf, "%s: slot %s: date %-8s label %s", - get_pname(), slotstr, datestamp, label); - if(searchlabel != NULL - && (strcmp(label, FAKE_LABEL) == 0 - || strcmp(label, searchlabel) == 0)) { - /* it's the one we are looking for, stop here */ - fprintf(errf, " (exact label match)\n"); - found_device = newstralloc(found_device, device); - found = 1; - return 1; - } - else if(!match(labelstr, label)) - fprintf(errf, " (no match)\n"); - else { - /* not an exact label match, but a labelstr match */ - /* check against tape list */ - tp = lookup_tapelabel(label); - if(tp == NULL) - fprintf(errf, " (Not in tapelist)\n"); - else if(!reusable_tape(tp)) - fprintf(errf, " (active tape)\n"); - else if(got_match == 0 && tp->datestamp == 0) { - got_match = 1; - first_match = newstralloc(first_match, slotstr); - first_match_label = newstralloc(first_match_label, label); - fprintf(errf, " (new tape)\n"); - found = 3; - found_device = newstralloc(found_device, device); - return 1; - } - else if(got_match) - fprintf(errf, " (labelstr match)\n"); - else { - got_match = 1; - first_match = newstralloc(first_match, slotstr); - first_match_label = newstralloc(first_match_label, label); - fprintf(errf, " (first labelstr match)\n"); - if(!backwards || !searchlabel) { - found = 2; - found_device = newstralloc(found_device, device); - return 1; - } - } - } - } - } - return 0; -} - -char *taper_scan() -{ - char *outslot = NULL; - - if((tp = lookup_last_reusable_tape(0)) == NULL) - searchlabel = NULL; - else - searchlabel = tp->label; - - found = 0; - got_match = 0; - - changer_find(scan_init, taperscan_slot, searchlabel); - - if(found == 2 || found == 3) - searchlabel = first_match_label; - else if(!found && got_match) { - searchlabel = first_match_label; - amfree(found_device); - if(changer_loadslot(first_match, &outslot, &found_device) == 0) { - found = 1; - } - } else if(!found) { - if(searchlabel) { - changer_resultstr = newvstralloc(changer_resultstr, - "label ", searchlabel, - " or new tape not found in rack", - NULL); - } else { - changer_resultstr = newstralloc(changer_resultstr, - "new tape not found in rack"); - } - } - amfree(outslot); - - return found ? found_device : NULL; -} - -int test_server_pgm(outf, dir, pgm, suid, dumpuid) -FILE *outf; -char *dir; -char *pgm; -int suid; -uid_t dumpuid; +FILE *errf = NULL; + +int +test_server_pgm( + FILE * outf, + char * dir, + char * pgm, + int suid, + uid_t dumpuid) { struct stat statbuf; int pgmbad = 0; + char *quoted; pgm = vstralloc(dir, "/", pgm, versionsuffix(), NULL); + quoted = quote_string(pgm); if(stat(pgm, &statbuf) == -1) { fprintf(outf, "ERROR: program %s: does not exist\n", - pgm); + quoted); pgmbad = 1; } else if (!S_ISREG(statbuf.st_mode)) { fprintf(outf, "ERROR: program %s: not a file\n", - pgm); + quoted); pgmbad = 1; } else if (access(pgm, X_OK) == -1) { fprintf(outf, "ERROR: program %s: not executable\n", - pgm); + quoted); pgmbad = 1; } else if (suid \ && dumpuid != 0 && (statbuf.st_uid != 0 || (statbuf.st_mode & 04000) == 0)) { - fprintf(outf, "WARNING: program %s: not setuid-root\n", - pgm); + fprintf(outf, "ERROR: program %s: not setuid-root\n", + quoted); + pgmbad = 1; } + amfree(quoted); amfree(pgm); return pgmbad; } -int start_server_check(fd, do_localchk, do_tapechk) - int fd; +pid_t +start_server_check( + int fd, + int do_localchk, + int do_tapechk) { - char *errstr, *tapename; + char *tapename; generic_fs_stats_t fs; - tape_t *tp; - FILE *outf; + FILE *outf = NULL; holdingdisk_t *hdp; - int pid; + pid_t pid; int confbad = 0, tapebad = 0, disklow = 0, logbad = 0; int userbad = 0, infobad = 0, indexbad = 0, pgmbad = 0; int testtape = do_tapechk; + tapetype_t *tp = NULL; + char *quoted; switch(pid = fork()) { - case -1: error("could not fork server check: %s", strerror(errno)); - case 0: break; + case -1: + error("could not fork server check: %s", strerror(errno)); + /*NOTREACHED*/ + + case 0: + break; + default: return pid; } @@ -678,24 +619,27 @@ int start_server_check(fd, do_localchk, do_tapechk) set_pname("amcheck-server"); - amfree(msg); - startclock(); - if((outf = fdopen(fd, "w")) == NULL) + if((outf = fdopen(fd, "w")) == NULL) { error("fdopen %d: %s", fd, strerror(errno)); + /*NOTREACHED*/ + } errf = outf; fprintf(outf, "Amanda Tape Server Host Check\n"); fprintf(outf, "-----------------------------\n"); + if (do_localchk || testtape) { + tp = lookup_tapetype(getconf_str(CNF_TAPETYPE)); + } + /* * Check various server side config file settings. */ if(do_localchk) { char *ColumnSpec; char *errstr = NULL; - tapetype_t *tp; char *lbl_templ; ColumnSpec = getconf_str(CNF_COLUMNSPEC); @@ -704,8 +648,7 @@ int start_server_check(fd, do_localchk, do_tapechk) amfree(errstr); confbad = 1; } - tp = lookup_tapetype(getconf_str(CNF_TAPETYPE)); - lbl_templ = tp->lbl_templ; + lbl_templ = tapetype_get_lbl_templ(tp); if(strcmp(lbl_templ, "") != 0) { if(strchr(lbl_templ, '/') == NULL) { lbl_templ = stralloc2(config_dir, lbl_templ); @@ -724,57 +667,61 @@ int start_server_check(fd, do_localchk, do_tapechk) confbad = 1; #endif } + + /* check that localhost is resolvable */ + if ((gethostbyname("localhost")) == NULL) { + fprintf(outf, "ERROR: Cannot resolve `localhost'.\n"); + } } /* * Look up the programs used on the server side. */ if(do_localchk) { + /* + * entreprise version will do planner/dumper suid check + */ if(access(libexecdir, X_OK) == -1) { + quoted = quote_string(libexecdir); fprintf(outf, "ERROR: program dir %s: not accessible\n", - libexecdir); + quoted); pgmbad = 1; + amfree(quoted); } else { - pgmbad = pgmbad \ - || test_server_pgm(outf, libexecdir, "planner", - 1, uid_dumpuser); - pgmbad = pgmbad \ - || test_server_pgm(outf, libexecdir, "dumper", - 1, uid_dumpuser); - pgmbad = pgmbad \ - || test_server_pgm(outf, libexecdir, "driver", - 0, uid_dumpuser); - pgmbad = pgmbad \ - || test_server_pgm(outf, libexecdir, "taper", - 0, uid_dumpuser); - pgmbad = pgmbad \ - || test_server_pgm(outf, libexecdir, "amtrmidx", - 0, uid_dumpuser); - pgmbad = pgmbad \ - || test_server_pgm(outf, libexecdir, "amlogroll", - 0, uid_dumpuser); + if(test_server_pgm(outf, libexecdir, "planner", 1, uid_dumpuser)) + pgmbad = 1; + if(test_server_pgm(outf, libexecdir, "dumper", 1, uid_dumpuser)) + pgmbad = 1; + if(test_server_pgm(outf, libexecdir, "driver", 0, uid_dumpuser)) + pgmbad = 1; + if(test_server_pgm(outf, libexecdir, "taper", 0, uid_dumpuser)) + pgmbad = 1; + if(test_server_pgm(outf, libexecdir, "amtrmidx", 0, uid_dumpuser)) + pgmbad = 1; + if(test_server_pgm(outf, libexecdir, "amlogroll", 0, uid_dumpuser)) + pgmbad = 1; } if(access(sbindir, X_OK) == -1) { + quoted = quote_string(sbindir); fprintf(outf, "ERROR: program dir %s: not accessible\n", sbindir); pgmbad = 1; + amfree(quoted); } else { - pgmbad = pgmbad \ - || test_server_pgm(outf, sbindir, "amgetconf", - 0, uid_dumpuser); - pgmbad = pgmbad \ - || test_server_pgm(outf, sbindir, "amcheck", - 1, uid_dumpuser); - pgmbad = pgmbad \ - || test_server_pgm(outf, sbindir, "amdump", - 0, uid_dumpuser); - pgmbad = pgmbad \ - || test_server_pgm(outf, sbindir, "amreport", - 0, uid_dumpuser); + if(test_server_pgm(outf, sbindir, "amgetconf", 0, uid_dumpuser)) + pgmbad = 1; + if(test_server_pgm(outf, sbindir, "amcheck", 1, uid_dumpuser)) + pgmbad = 1; + if(test_server_pgm(outf, sbindir, "amdump", 0, uid_dumpuser)) + pgmbad = 1; + if(test_server_pgm(outf, sbindir, "amreport", 0, uid_dumpuser)) + pgmbad = 1; } if(access(COMPRESS_PATH, X_OK) == -1) { + quoted = quote_string(COMPRESS_PATH); fprintf(outf, "WARNING: %s is not executable, server-compression and indexing will not work\n", - COMPRESS_PATH); + quoted); + amfree(quoted); } } @@ -791,7 +738,8 @@ int start_server_check(fd, do_localchk, do_tapechk) char *tape_dir; char *lastslash; char *holdfile; - + struct stat statbuf; + conf_tapelist=getconf_str(CNF_TAPELIST); if (*conf_tapelist == '/') { tapefile = stralloc(conf_tapelist); @@ -809,18 +757,47 @@ int start_server_check(fd, do_localchk, do_tapechk) */ } if(access(tape_dir, W_OK) == -1) { - fprintf(outf, "ERROR: tapelist dir %s: not writable\n", tape_dir); + quoted = quote_string(tape_dir); + fprintf(outf, "ERROR: tapelist dir %s: not writable.\n", quoted); tapebad = 1; + amfree(quoted); + } + else if(stat(tapefile, &statbuf) == -1) { + quoted = quote_string(tape_dir); + fprintf(outf, "ERROR: tapefile %s (%s), " + "you must create an empty file.\n", + quoted, strerror(errno)); + tapebad = 1; + amfree(quoted); + } + else if(!S_ISREG(statbuf.st_mode)) { + quoted = quote_string(tapefile); + fprintf(outf, "ERROR: tapefile %s: should be a regular file.\n", + quoted); + tapebad = 1; + amfree(quoted); + } + else if(access(tapefile, F_OK) != 0) { + quoted = quote_string(tapefile); + fprintf(outf, "ERROR: can't access tape list %s\n", quoted); + tapebad = 1; + amfree(quoted); } else if(access(tapefile, F_OK) == 0 && access(tapefile, W_OK) != 0) { - fprintf(outf, "ERROR: tape list %s: not writable\n", tapefile); + quoted = quote_string(tapefile); + fprintf(outf, "ERROR: tape list %s: not writable\n", quoted); tapebad = 1; + amfree(quoted); } else if(read_tapelist(tapefile)) { - fprintf(outf, "ERROR: tape list %s: parse error\n", tapefile); + quoted = quote_string(tapefile); + fprintf(outf, "ERROR: tape list %s: parse error\n", quoted); tapebad = 1; + amfree(quoted); } holdfile = vstralloc(config_dir, "/", "hold", NULL); if(access(holdfile, F_OK) != -1) { + quoted = quote_string(holdfile); fprintf(outf, "WARNING: hold file %s exists\n", holdfile); + amfree(quoted); } amfree(tapefile); amfree(tape_dir); @@ -839,46 +816,73 @@ int start_server_check(fd, do_localchk, do_tapechk) if(do_localchk) { for(hdp = holdingdisks; hdp != NULL; hdp = hdp->next) { - if(get_fs_stats(hdp->diskdir, &fs) == -1) { - fprintf(outf, "ERROR: holding disk %s: statfs: %s\n", - hdp->diskdir, strerror(errno)); + quoted = quote_string(holdingdisk_get_diskdir(hdp)); + if(get_fs_stats(holdingdisk_get_diskdir(hdp), &fs) == -1) { + fprintf(outf, "ERROR: holding dir %s (%s), " + "you must create a directory.\n", + quoted, strerror(errno)); disklow = 1; } - else if(access(hdp->diskdir, W_OK) == -1) { - fprintf(outf, "ERROR: holding disk %s: not writable: %s\n", - hdp->diskdir, strerror(errno)); + else if(access(holdingdisk_get_diskdir(hdp), W_OK) == -1) { + fprintf(outf, "ERROR: holding disk %s: not writable: %s.\n", + quoted, strerror(errno)); disklow = 1; } - else if(fs.avail == -1) { + else if(access(holdingdisk_get_diskdir(hdp), X_OK) == -1) { + fprintf(outf, "ERROR: holding disk %s: not searcheable: %s.\n", + quoted, strerror(errno)); + disklow = 1; + } + else if(fs.avail == (off_t)-1) { fprintf(outf, - "WARNING: holding disk %s: available space unknown (%ld KB requested)\n", - hdp->diskdir, (long)hdp->disksize); + "WARNING: holding disk %s: " + "available space unknown (" OFF_T_FMT" KB requested)\n", + quoted, (OFF_T_FMT_TYPE)holdingdisk_get_disksize(hdp)); disklow = 1; } - else if(hdp->disksize > 0) { - if(fs.avail < hdp->disksize) { + else if(holdingdisk_get_disksize(hdp) > (off_t)0) { + if(fs.avail < holdingdisk_get_disksize(hdp)) { fprintf(outf, - "WARNING: holding disk %s: only %ld KB free (%ld KB requested)\n", - hdp->diskdir, (long)fs.avail, (long)hdp->disksize); + "WARNING: holding disk %s: " + "only " OFF_T_FMT " %sB free (" + OFF_T_FMT " %sB requested)\n", quoted, + (OFF_T_FMT_TYPE)(fs.avail / (off_t)unitdivisor), + displayunit, + (OFF_T_FMT_TYPE)(holdingdisk_get_disksize(hdp)/(off_t)unitdivisor), + displayunit); disklow = 1; } - else + else { fprintf(outf, - "Holding disk %s: %ld KB disk space available, that's plenty\n", - hdp->diskdir, fs.avail); + "Holding disk %s: " OFF_T_FMT + " %sB disk space available, that's plenty\n", + quoted, (OFF_T_FMT_TYPE)(fs.avail/(off_t)unitdivisor), + displayunit); + } } else { - if(fs.avail < -hdp->disksize) { + assert(holdingdisk_get_disksize(hdp) < (off_t)0); + if((fs.avail + holdingdisk_get_disksize(hdp)) <= (off_t)0) { fprintf(outf, - "WARNING: holding disk %s: only %ld KB free, using nothing\n", - hdp->diskdir, fs.avail); + "WARNING: holding disk %s: " + "only " OFF_T_FMT " %sB free, using nothing\n", + quoted, (OFF_T_FMT_TYPE)(fs.avail/(off_t)unitdivisor), + displayunit); disklow = 1; } - else + else { fprintf(outf, - "Holding disk %s: %ld KB disk space available, using %ld KB\n", - hdp->diskdir, fs.avail, fs.avail + hdp->disksize); + "Holding disk %s: " + OFF_T_FMT " %sB disk space available, using " + OFF_T_FMT " %sB\n", + quoted, + (OFF_T_FMT_TYPE)(fs.avail/(off_t)unitdivisor), + displayunit, + (OFF_T_FMT_TYPE)(fs.avail + holdingdisk_get_disksize(hdp) / (off_t)unitdivisor), + displayunit); + } } + amfree(quoted); } } @@ -889,6 +893,7 @@ int start_server_check(fd, do_localchk, do_tapechk) char *logfile; char *olddir; struct stat stat_old; + struct stat statbuf; conf_logdir = getconf_str(CNF_LOGDIR); if (*conf_logdir == '/') { @@ -898,31 +903,44 @@ int start_server_check(fd, do_localchk, do_tapechk) } logfile = vstralloc(conf_logdir, "/log", NULL); - if(access(conf_logdir, W_OK) == -1) { - fprintf(outf, "ERROR: log dir %s: not writable\n", conf_logdir); + quoted = quote_string(conf_logdir); + if(stat(conf_logdir, &statbuf) == -1) { + fprintf(outf, "ERROR: logdir %s (%s), you must create directory.\n", + quoted, strerror(errno)); + disklow = 1; + } + else if(access(conf_logdir, W_OK) == -1) { + fprintf(outf, "ERROR: log dir %s: not writable\n", quoted); logbad = 1; } + amfree(quoted); if(access(logfile, F_OK) == 0) { testtape = 0; logbad = 1; - if(access(logfile, W_OK) != 0) - fprintf(outf, "ERROR: log file %s: not writable\n", - logfile); + if(access(logfile, W_OK) != 0) { + quoted = quote_string(logfile); + fprintf(outf, "ERROR: log file %s: not writable\n", quoted); + amfree(quoted); + } } olddir = vstralloc(conf_logdir, "/oldlog", NULL); + quoted = quote_string(olddir); if (stat(olddir,&stat_old) == 0) { /* oldlog exist */ if(!(S_ISDIR(stat_old.st_mode))) { - fprintf(outf, "ERROR: oldlog directory \"%s\" is not a directory\n", olddir); + fprintf(outf, "ERROR: oldlog directory %s is not a directory\n", + quoted); } if(access(olddir, W_OK) == -1) { - fprintf(outf, "ERROR: oldlog dir %s: not writable\n", olddir); + fprintf(outf, "ERROR: oldlog dir %s: not writable\n", quoted); } } else if(lstat(olddir,&stat_old) == 0) { - fprintf(outf, "ERROR: oldlog directory \"%s\" is not a directory\n", olddir); + fprintf(outf, "ERROR: oldlog directory %s is not a directory\n", + quoted); } + amfree(quoted); if (testtape) { logfile = newvstralloc(logfile, conf_logdir, "/amdump", NULL); @@ -932,12 +950,14 @@ int start_server_check(fd, do_localchk, do_tapechk) } } + amfree(olddir); amfree(logfile); amfree(conf_logdir); } if (testtape) { /* check that the tape is a valid amanda tape */ + int tape_status; tapedays = getconf_int(CNF_TAPECYCLE); labelstr = getconf_str(CNF_LABELSTR); @@ -948,56 +968,49 @@ int start_server_check(fd, do_localchk, do_tapechk) "WARNING: if a tape changer is not available, runtapes must be set to 1\n"); } - if(changer_init() && (tapename = taper_scan()) == NULL) { - fprintf(outf, "ERROR: %s\n", changer_resultstr); - tapebad = 1; - } else if(tape_access(tapename,F_OK|R_OK|W_OK) == -1) { - fprintf(outf, "ERROR: %s: %s\n", tapename, strerror(errno)); - tapebad = 1; - } else if((errstr = tape_rdlabel(tapename, &datestamp, &label)) != NULL) { - fprintf(outf, "ERROR: %s: %s\n", tapename, errstr); - tapebad = 1; - } else if(strcmp(label, FAKE_LABEL) != 0) { - if(!match(labelstr, label)) { - fprintf(outf, "ERROR: label %s doesn't match labelstr \"%s\"\n", - label, labelstr); - tapebad = 1; - } - else { - tp = lookup_tapelabel(label); - if(tp == NULL) { - fprintf(outf, "ERROR: label %s match labelstr but it not listed in the tapelist file.\n", label); - tapebad = 1; - } - else if(tp != NULL && !reusable_tape(tp)) { - fprintf(outf, "ERROR: cannot overwrite active tape %s\n", - label); - tapebad = 1; - } - } - - } - - if(tapebad) { + tape_status = taper_scan(NULL, &label, &datestamp, &tapename, + FILE_taperscan_output_callback, outf); + if (tape_status < 0) { tape_t *exptape = lookup_last_reusable_tape(0); fprintf(outf, " (expecting "); if(exptape != NULL) fprintf(outf, "tape %s or ", exptape->label); fprintf(outf, "a new tape)\n"); - } - - if(!tapebad && overwrite) { - if((errstr = tape_writable(tapename)) != NULL) { - fprintf(outf, - "ERROR: tape %s label ok, but is not writable\n", - label); - tapebad = 1; - } - else fprintf(outf, "Tape %s is writable\n", label); - } - else fprintf(outf, "NOTE: skipping tape-writable test\n"); - - if(!tapebad) - fprintf(outf, "Tape %s label ok\n", label); + tapebad = 1; + } else { + if (overwrite) { + char *wrlabel_status; + wrlabel_status = tape_wrlabel(tapename, "X", label, + (unsigned)(tapetype_get_blocksize(tp) * 1024)); + if (wrlabel_status != NULL) { + if (tape_status == 3) { + fprintf(outf, + "ERROR: Could not label brand new tape: %s\n", + wrlabel_status); + } else { + fprintf(outf, + "ERROR: tape %s label ok, but is not writable (%s)\n", + label, wrlabel_status); + } + tapebad = 1; + } else { + if (tape_status != 3) { + fprintf(outf, "Tape %s is writable; rewrote label.\n", label); + } else { + fprintf(outf, "Wrote label %s to brand new tape.\n", label); + } + } + } else { + fprintf(outf, "NOTE: skipping tape-writable test\n"); + if (tape_status == 3) { + fprintf(outf, + "Found a brand new tape, will label it %s.\n", + label); + } else { + fprintf(outf, "Tape %s label ok\n", label); + } + } + } + amfree(tapename); } else if (do_tapechk) { fprintf(outf, "WARNING: skipping tape test because amdump or amflush seem to be running\n"); fprintf(outf, "WARNING: if they are not, you must run amcleanup\n"); @@ -1019,7 +1032,7 @@ int start_server_check(fd, do_localchk, do_tapechk) char *infofile = NULL; struct stat statbuf; disk_t *dp; - host_t *hostp; + am_host_t *hostp; int indexdir_checked = 0; int hostindexdir_checked = 0; char *host; @@ -1034,154 +1047,243 @@ int start_server_check(fd, do_localchk, do_tapechk) conf_tapecycle, conf_runspercycle); } - conf_infofile = stralloc(getconf_str(CNF_INFOFILE)); - if (*conf_infofile != '/') { - char *ci = stralloc2(config_dir, conf_infofile); - amfree(conf_infofile); - conf_infofile = ci; + conf_infofile = getconf_str(CNF_INFOFILE); + if (*conf_infofile == '/') { + conf_infofile = stralloc(conf_infofile); + } else { + conf_infofile = stralloc2(config_dir, conf_infofile); } - conf_indexdir = stralloc(getconf_str(CNF_INDEXDIR)); - if (*conf_indexdir != '/') { - char *ci = stralloc2(config_dir, conf_indexdir); - amfree(conf_indexdir); - conf_indexdir = ci; + + conf_indexdir = getconf_str(CNF_INDEXDIR); + if (*conf_indexdir == '/') { + conf_indexdir = stralloc(conf_indexdir); + } else { + conf_indexdir = stralloc2(config_dir, conf_indexdir); } + #if TEXTDB + quoted = quote_string(conf_infofile); if(stat(conf_infofile, &statbuf) == -1) { - fprintf(outf, "NOTE: info dir %s: does not exist\n", conf_infofile); - fprintf(outf, "NOTE: it will be created on the next run\n"); + if (errno == ENOENT) { + fprintf(outf, "NOTE: conf info dir %s does not exist\n", + quoted); + fprintf(outf, "NOTE: it will be created on the next run.\n"); + } else { + fprintf(outf, "ERROR: conf info dir %s (%s)\n", + quoted, strerror(errno)); + } amfree(conf_infofile); } else if (!S_ISDIR(statbuf.st_mode)) { - fprintf(outf, "ERROR: info dir %s: not a directory\n", conf_infofile); + fprintf(outf, "ERROR: info dir %s: not a directory\n", quoted); amfree(conf_infofile); infobad = 1; } else if (access(conf_infofile, W_OK) == -1) { - fprintf(outf, "ERROR: info dir %s: not writable\n", conf_infofile); + fprintf(outf, "ERROR: info dir %s: not writable\n", quoted); amfree(conf_infofile); infobad = 1; } else { strappend(conf_infofile, "/"); } + amfree(quoted); #endif - while(!empty(*origqp)) { - hostp = origqp->head->host; + + while(!empty(origq)) { + hostp = origq.head->host; host = sanitise_filename(hostp->hostname); #if TEXTDB if(conf_infofile) { hostinfodir = newstralloc2(hostinfodir, conf_infofile, host); + quoted = quote_string(hostinfodir); if(stat(hostinfodir, &statbuf) == -1) { - fprintf(outf, "NOTE: info dir %s: does not exist\n", - hostinfodir); + if (errno == ENOENT) { + fprintf(outf, "NOTE: host info dir %s does not exist\n", + quoted); + fprintf(outf, + "NOTE: it will be created on the next run.\n"); + } else { + fprintf(outf, "ERROR: host info dir %s (%s)\n", + quoted, strerror(errno)); + } amfree(hostinfodir); } else if (!S_ISDIR(statbuf.st_mode)) { fprintf(outf, "ERROR: info dir %s: not a directory\n", - hostinfodir); + quoted); amfree(hostinfodir); infobad = 1; } else if (access(hostinfodir, W_OK) == -1) { - fprintf(outf, "ERROR: info dir %s: not writable\n", - hostinfodir); + fprintf(outf, "ERROR: info dir %s: not writable\n", quoted); amfree(hostinfodir); infobad = 1; } else { strappend(hostinfodir, "/"); } + amfree(quoted); } #endif for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) { disk = sanitise_filename(dp->name); #if TEXTDB if(hostinfodir) { + char *quotedif; + diskdir = newstralloc2(diskdir, hostinfodir, disk); infofile = vstralloc(diskdir, "/", "info", NULL); + quoted = quote_string(diskdir); + quotedif = quote_string(infofile); if(stat(diskdir, &statbuf) == -1) { - fprintf(outf, "NOTE: info dir %s: does not exist\n", - diskdir); + if (errno == ENOENT) { + fprintf(outf, "NOTE: info dir %s does not exist\n", + quoted); + fprintf(outf, + "NOTE: it will be created on the next run.\n"); + } else { + fprintf(outf, "ERROR: info dir %s (%s)\n", + quoted, strerror(errno)); + } } else if (!S_ISDIR(statbuf.st_mode)) { fprintf(outf, "ERROR: info dir %s: not a directory\n", - diskdir); + quoted); infobad = 1; } else if (access(diskdir, W_OK) == -1) { fprintf(outf, "ERROR: info dir %s: not writable\n", - diskdir); + quoted); infobad = 1; } else if(stat(infofile, &statbuf) == -1) { - fprintf(outf, "WARNING: info file %s: does not exist\n", - infofile); + if (errno == ENOENT) { + fprintf(outf, "NOTE: info file %s does not exist\n", + quotedif); + fprintf(outf, "NOTE: it will be created on the next run.\n"); + } else { + fprintf(outf, "ERROR: info dir %s (%s)\n", + quoted, strerror(errno)); + } } else if (!S_ISREG(statbuf.st_mode)) { fprintf(outf, "ERROR: info file %s: not a file\n", - infofile); + quotedif); infobad = 1; } else if (access(infofile, R_OK) == -1) { fprintf(outf, "ERROR: info file %s: not readable\n", - infofile); + quotedif); infobad = 1; } + amfree(quotedif); + amfree(quoted); amfree(infofile); } #endif if(dp->index) { if(! indexdir_checked) { + quoted = quote_string(conf_indexdir); if(stat(conf_indexdir, &statbuf) == -1) { - fprintf(outf, "NOTE: index dir %s: does not exist\n", - conf_indexdir); + if (errno == ENOENT) { + fprintf(outf, "NOTE: index dir %s does not exist\n", + quoted); + fprintf(outf, "NOTE: it will be created on the next run.\n"); + } else { + fprintf(outf, "ERROR: index dir %s (%s)\n", + quoted, strerror(errno)); + } amfree(conf_indexdir); } else if (!S_ISDIR(statbuf.st_mode)) { fprintf(outf, "ERROR: index dir %s: not a directory\n", - conf_indexdir); + quoted); amfree(conf_indexdir); indexbad = 1; } else if (access(conf_indexdir, W_OK) == -1) { fprintf(outf, "ERROR: index dir %s: not writable\n", - conf_indexdir); + quoted); amfree(conf_indexdir); indexbad = 1; } else { strappend(conf_indexdir, "/"); } indexdir_checked = 1; + amfree(quoted); } if(conf_indexdir) { if(! hostindexdir_checked) { hostindexdir = stralloc2(conf_indexdir, host); + quoted = quote_string(hostindexdir); if(stat(hostindexdir, &statbuf) == -1) { - fprintf(outf, "NOTE: index dir %s: does not exist\n", - hostindexdir); + if (errno == ENOENT) { + fprintf(outf, "NOTE: index dir %s does not exist\n", + quoted); + fprintf(outf, "NOTE: it will be created on the next run.\n"); + } else { + fprintf(outf, "ERROR: index dir %s (%s)\n", + quoted, strerror(errno)); + } amfree(hostindexdir); } else if (!S_ISDIR(statbuf.st_mode)) { fprintf(outf, "ERROR: index dir %s: not a directory\n", - hostindexdir); + quoted); amfree(hostindexdir); indexbad = 1; } else if (access(hostindexdir, W_OK) == -1) { fprintf(outf, "ERROR: index dir %s: not writable\n", - hostindexdir); + quoted); amfree(hostindexdir); indexbad = 1; } else { strappend(hostindexdir, "/"); } hostindexdir_checked = 1; + amfree(quoted); } if(hostindexdir) { diskdir = newstralloc2(diskdir, hostindexdir, disk); + quoted = quote_string(diskdir); if(stat(diskdir, &statbuf) == -1) { - fprintf(outf, "NOTE: index dir %s: does not exist\n", - diskdir); + if (errno == ENOENT) { + fprintf(outf, "NOTE: index dir %s does not exist\n", + quoted); + fprintf(outf, "NOTE: it will be created on the next run.\n"); + } else { + fprintf(outf, "ERROR: index dir %s (%s)\n", + quoted, strerror(errno)); + } } else if (!S_ISDIR(statbuf.st_mode)) { fprintf(outf, "ERROR: index dir %s: not a directory\n", - diskdir); + quoted); indexbad = 1; } else if (access(diskdir, W_OK) == -1) { fprintf(outf, "ERROR: index dir %s: is not writable\n", - diskdir); + quoted); indexbad = 1; } + amfree(quoted); } } } + + if ( dp->encrypt == ENCRYPT_SERV_CUST ) { + if ( dp->srv_encrypt[0] == '\0' ) { + fprintf(outf, "ERROR: server encryption program not specified\n"); + pgmbad = 1; + } + else if(access(dp->srv_encrypt, X_OK) == -1) { + fprintf(outf, "ERROR: %s is not executable, server encryption will not work\n", + dp->srv_encrypt ); + pgmbad = 1; + } + } + if ( dp->compress == COMP_SERV_CUST ) { + if ( dp->srvcompprog[0] == '\0' ) { + fprintf(outf, "ERROR: server custom compression program not specified\n"); + pgmbad = 1; + } + else if(access(dp->srvcompprog, X_OK) == -1) { + quoted = quote_string(dp->srvcompprog); + + fprintf(outf, "ERROR: %s is not executable, server custom compression will not work\n", + quoted); + amfree(quoted); + pgmbad = 1; + } + } + amfree(disk); - remove_disk(origqp, dp); + remove_disk(&origq, dp); } amfree(host); amfree(hostindexdir); @@ -1216,7 +1318,7 @@ int start_server_check(fd, do_localchk, do_tapechk) || infobad \ || indexbad \ || pgmbad); - /* NOTREACHED */ + /*NOTREACHED*/ return 0; } @@ -1224,13 +1326,9 @@ int start_server_check(fd, do_localchk, do_tapechk) int remote_errors; FILE *outf; -int amanda_port; -#ifdef KRB4_SECURITY -int kamanda_port; -#endif - -static void handle_response P((proto_t *p, pkt_t *pkt)); +static void handle_result(void *, pkt_t *, security_handle_t *); +void start_host(am_host_t *hostp); #define HOST_READY ((void *)0) /* must be 0 */ #define HOST_ACTIVE ((void *)1) @@ -1240,18 +1338,25 @@ static void handle_response P((proto_t *p, pkt_t *pkt)); #define DISK_ACTIVE ((void *)1) #define DISK_DONE ((void *)2) -int start_host(hostp) - host_t *hostp; +void +start_host( + am_host_t *hostp) { disk_t *dp; char *req = NULL; - int req_len = 0; - int rc; + size_t req_len = 0; int disk_count; + const security_driver_t *secdrv; char number[NUM_STR_SIZE]; if(hostp->up != HOST_READY) { - return 0; + return; + } + + if (strncmp (hostp->hostname,"localhost",9) == 0) { + fprintf(outf, + "WARNING: Usage of fully qualified hostname recommended for Client %s.\n", + hostp->hostname); } /* @@ -1269,6 +1374,8 @@ int start_host(hostp) fe_req_options_hostname); int has_maxdumps = am_has_feature(hostp->features, fe_req_options_maxdumps); + int has_config = am_has_feature(hostp->features, + fe_req_options_config); if(!am_has_feature(hostp->features, fe_selfcheck_req) && !am_has_feature(hostp->features, fe_selfcheck_req_device)) { @@ -1305,7 +1412,7 @@ int start_host(hostp) hostp->hostname); } - ap_snprintf(number, sizeof(number), "%d", hostp->maxdumps); + snprintf(number, SIZEOF(number), "%d", hostp->maxdumps); req = vstralloc("SERVICE ", "selfcheck", "\n", "OPTIONS ", has_features ? "features=" : "", @@ -1317,76 +1424,149 @@ int start_host(hostp) has_hostname ? "hostname=" : "", has_hostname ? hostp->hostname : "", has_hostname ? ";" : "", + has_config ? "config=" : "", + has_config ? config_name : "", + has_config ? ";" : "", "\n", NULL); req_len = strlen(req); - req_len += 128; /* room for SECURITY ... */ - req_len += 256; /* room for non-disk answers */ + req_len += 128; /* room for SECURITY ... */ + req_len += 256; /* room for non-disk answers */ for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) { char *l; - int l_len; + size_t l_len; char *o; + char *calcsize; + char *qname; + char *qdevice; - if(dp->todo == 0) continue; - - if(dp->up != DISK_READY) { + if(dp->up != DISK_READY || dp->todo != 1) { continue; } o = optionstr(dp, hostp->features, outf); + if (o == NULL) { + remote_errors++; + continue; + } + qname = quote_string(dp->name); + qdevice = quote_string(dp->device); + if ((dp->name && qname[0] == '"') || + (dp->device && qdevice[0] == '"')) { + if(!am_has_feature(hostp->features, fe_interface_quoted_text)) { + fprintf(outf, + "WARNING: %s:%s:%s host does not support quoted text\n", + hostp->hostname, qname, qdevice); + } + } if(dp->device) { if(!am_has_feature(hostp->features, fe_selfcheck_req_device)) { fprintf(outf, "ERROR: %s:%s (%s): selfcheck does not support device.\n", - hostp->hostname, dp->name, dp->device); + hostp->hostname, qname, dp->device); } if(!am_has_feature(hostp->features, fe_sendsize_req_device)) { fprintf(outf, "ERROR: %s:%s (%s): sendsize does not support device.\n", - hostp->hostname, dp->name, dp->device); + hostp->hostname, qname, dp->device); } if(!am_has_feature(hostp->features, fe_sendbackup_req_device)) { fprintf(outf, "ERROR: %s:%s (%s): sendbackup does not support device.\n", - hostp->hostname, dp->name, dp->device); + hostp->hostname, qname, dp->device); } } - if(strcmp(dp->program, "DUMP") == 0 && - !am_has_feature(hostp->features, fe_program_dump)) { - fprintf(outf, "ERROR: %s:%s does not support DUMP.\n", - hostp->hostname, dp->name); - } - if(strcmp(dp->program, "GNUTAR") == 0 && - !am_has_feature(hostp->features, fe_program_gnutar)) { - fprintf(outf, "ERROR: %s:%s does not support GNUTAR.\n", - hostp->hostname, dp->name); + if(strncmp(dp->program,"DUMP",4) == 0 || + strncmp(dp->program,"GNUTAR",6) == 0) { + if(strcmp(dp->program, "DUMP") == 0 && + !am_has_feature(hostp->features, fe_program_dump)) { + fprintf(outf, "ERROR: %s:%s does not support DUMP.\n", + hostp->hostname, qname); + } + if(strcmp(dp->program, "GNUTAR") == 0 && + !am_has_feature(hostp->features, fe_program_gnutar)) { + fprintf(outf, "ERROR: %s:%s does not support GNUTAR.\n", + hostp->hostname, qname); + } + if(dp->estimate == ES_CALCSIZE && + !am_has_feature(hostp->features, fe_calcsize_estimate)) { + fprintf(outf, "ERROR: %s:%s does not support CALCSIZE for estimate, using CLIENT.\n", + hostp->hostname, qname); + dp->estimate = ES_CLIENT; + } + if(dp->estimate == ES_CALCSIZE && + am_has_feature(hostp->features, fe_selfcheck_calcsize)) + calcsize = "CALCSIZE "; + else + calcsize = ""; + + if(dp->compress == COMP_CUST && + !am_has_feature(hostp->features, fe_options_compress_cust)) { + fprintf(outf, + "ERROR: Client %s does not support custom compression.\n", + hostp->hostname); + } + if(dp->encrypt == ENCRYPT_CUST ) { + if ( !am_has_feature(hostp->features, fe_options_encrypt_cust)) { + fprintf(outf, + "ERROR: Client %s does not support data encryption.\n", + hostp->hostname); + remote_errors++; + } else if ( dp->compress == COMP_SERV_FAST || + dp->compress == COMP_SERV_BEST || + dp->compress == COMP_SERV_CUST ) { + fprintf(outf, + "ERROR: %s: Client encryption with server compression is not supported. See amanda.conf(5) for detail.\n", hostp->hostname); + remote_errors++; + } + } + if(dp->device) { + l = vstralloc(calcsize, + dp->program, " ", + qname, " ", + dp->device, + " 0 OPTIONS |", + o, + "\n", + NULL); + } + else { + l = vstralloc(calcsize, + dp->program, " ", + qname, + " 0 OPTIONS |", + o, + "\n", + NULL); + } + } else { + if(!am_has_feature(hostp->features, fe_program_dumper_api)) { + fprintf(outf, "ERROR: %s:%s does not support DUMPER-API.\n", + hostp->hostname, qname); + } + l = vstralloc("DUMPER ", + dp->program, + " ", + qname, + " ", + dp->device, + " 0 OPTIONS |", + o, + "\n", + NULL); } - l = vstralloc(dp->program, - " ", - dp->name, - " ", - dp->device ? dp->device : "", - " 0 OPTIONS |", - o, - "\n", - NULL); + amfree(qname); + amfree(qdevice); l_len = strlen(l); amfree(o); - /* - * Allow 2X for error response in return packet. - */ - if(req_len + l_len > MAX_DGRAM / 2) { - amfree(l); - break; - } + strappend(req, l); req_len += l_len; amfree(l); dp->up = DISK_ACTIVE; disk_count++; } - } else { /* noop service */ req = vstralloc("SERVICE ", "noop", "\n", @@ -1395,55 +1575,51 @@ int start_host(hostp) "\n", NULL); for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) { - if(dp->todo == 0) continue; - - if(dp->up != DISK_READY) { + if(dp->up != DISK_READY || dp->todo != 1) { continue; } disk_count++; } } + if(disk_count == 0) { amfree(req); hostp->up = HOST_DONE; - return 0; + return; } -#ifdef KRB4_SECURITY - if(hostp->disks->auth == AUTH_KRB4) - rc = make_krb_request(hostp->hostname, kamanda_port, req, - hostp, conf_ctimeout, handle_response); - else -#endif - rc = make_request(hostp->hostname, amanda_port, req, - hostp, conf_ctimeout, handle_response); + secdrv = security_getdriver(hostp->disks->security_driver); + if (secdrv == NULL) { + error("could not find security driver '%s' for host '%s'", + hostp->disks->security_driver, hostp->hostname); + /*NOTREACHED*/ + } + protocol_sendreq(hostp->hostname, secdrv, amhost_get_security_conf, + req, conf_ctimeout, handle_result, hostp); - req = NULL; /* do not own this any more */ + amfree(req); - if(rc) { - /* couldn't resolve hostname */ - fprintf(outf, - "ERROR: %s: could not resolve hostname\n", hostp->hostname); - remote_errors++; - hostp->up = HOST_DONE; - } else { - hostp->up = HOST_ACTIVE; - } - return 1; + hostp->up = HOST_ACTIVE; } -int start_client_checks(fd) -int fd; +pid_t +start_client_checks( + int fd) { - host_t *hostp; + am_host_t *hostp; disk_t *dp; - int hostcount, pid; - struct servent *amandad; + int hostcount; + pid_t pid; int userbad = 0; switch(pid = fork()) { - case -1: error("could not fork client check: %s", strerror(errno)); - case 0: break; + case -1: + error("could not fork client check: %s", strerror(errno)); + /*NOTREACHED*/ + + case 0: + break; + default: return pid; } @@ -1455,46 +1631,29 @@ int fd; startclock(); - if((outf = fdopen(fd, "w")) == NULL) + if((outf = fdopen(fd, "w")) == NULL) { error("fdopen %d: %s", fd, strerror(errno)); + /*NOTREACHED*/ + } errf = outf; fprintf(outf, "\nAmanda Backup Client Hosts Check\n"); fprintf(outf, "--------------------------------\n"); -#ifdef KRB4_SECURITY - kerberos_service_init(); -#endif - - proto_init(msg->socket, time(0), 1024); - - /* get remote service port */ - if((amandad = getservbyname(AMANDA_SERVICE_NAME, "udp")) == NULL) - amanda_port = AMANDA_SERVICE_DEFAULT; - else - amanda_port = ntohs(amandad->s_port); - -#ifdef KRB4_SECURITY - if((amandad = getservbyname(KAMANDA_SERVICE_NAME, "udp")) == NULL) - kamanda_port = KAMANDA_SERVICE_DEFAULT; - else - kamanda_port = ntohs(amandad->s_port); -#endif + protocol_init(); hostcount = remote_errors = 0; - for(dp = origqp->head; dp != NULL; dp = dp->next) { + for(dp = origq.head; dp != NULL; dp = dp->next) { hostp = dp->host; - if(hostp->up == HOST_READY) { - if(start_host(hostp) == 1) { - hostcount++; - check_protocol(); - } + if(hostp->up == HOST_READY && dp->todo == 1) { + start_host(hostp); + hostcount++; + protocol_check(); } } - run_protocol(); - amfree(msg); + protocol_run(); fprintf(outf, "Client check: %d host%s checked in %s seconds, %d problem%s found\n", @@ -1513,15 +1672,17 @@ int fd; } exit(userbad || remote_errors > 0); - /* NOTREACHED */ + /*NOTREACHED*/ return 0; } -static void handle_response(p, pkt) -proto_t *p; -pkt_t *pkt; +static void +handle_result( + void * datap, + pkt_t * pkt, + security_handle_t * sech) { - host_t *hostp; + am_host_t *hostp; disk_t *dp; char *line; char *s; @@ -1529,58 +1690,40 @@ pkt_t *pkt; int ch; int tch; - hostp = (host_t *) p->datap; + hostp = (am_host_t *)datap; hostp->up = HOST_READY; - if(p->state == S_FAILED && pkt == NULL) { - if(p->prevstate == S_REPWAIT) { - fprintf(outf, - "WARNING: %s: selfcheck reply timed out.\n", - hostp->hostname); - } - else { - fprintf(outf, - "WARNING: %s: selfcheck request timed out. Host down?\n", - hostp->hostname); - } - remote_errors++; - hostp->up = HOST_DONE; - return; - } - -#ifdef KRB4_SECURITY - if(hostp->disks->auth == AUTH_KRB4 && - !check_mutual_authenticator(host2key(hostp->hostname), pkt, p)) { - fprintf(outf, "ERROR: %s [mutual-authentication failed]\n", - hostp->hostname); + if (pkt == NULL) { + fprintf(outf, + "WARNING: %s: selfcheck request failed: %s\n", hostp->hostname, + security_geterror(sech)); remote_errors++; hostp->up = HOST_DONE; return; } -#endif #if 0 - fprintf(errf, "got %sresponse from %s:\n----\n%s----\n\n", - (p->state == S_FAILED) ? "NAK " : "", hostp->hostname, pkt->body); + fprintf(errf, "got response from %s:\n----\n%s----\n\n", + hostp->hostname, pkt->body); #endif s = pkt->body; ch = *s++; while(ch) { line = s - 1; - skip_line(s, ch); + skip_quoted_line(s, ch); if (s[-2] == '\n') { s[-2] = '\0'; } #define sc "OPTIONS " - if(strncmp(line, sc, sizeof(sc)-1) == 0) { + if(strncmp(line, sc, SIZEOF(sc)-1) == 0) { #undef sc #define sc "features=" t = strstr(line, sc); if(t != NULL && (isspace((int)t[-1]) || t[-1] == ';')) { - t += sizeof(sc)-1; + t += SIZEOF(sc)-1; #undef sc am_release_feature_set(hostp->features); if((hostp->features = am_string_to_feature(t)) == NULL) { @@ -1593,14 +1736,14 @@ pkt_t *pkt; } #define sc "OK " - if(strncmp(line, sc, sizeof(sc)-1) == 0) { -#undef sc + if(strncmp(line, sc, SIZEOF(sc)-1) == 0) { continue; +#undef sc } #define sc "ERROR " - if(strncmp(line, sc, sizeof(sc)-1) == 0) { - t = line + sizeof(sc)-1; + if(strncmp(line, sc, SIZEOF(sc)-1) == 0) { + t = line + SIZEOF(sc) - 1; tch = t[-1]; #undef sc @@ -1610,15 +1753,13 @@ pkt_t *pkt; * just means the client is "old" (does not support the service). * We can ignore this. */ - if(hostp->features == NULL - && p->state == S_FAILED - && (strcmp(t - 1, "unknown service: noop") == 0 - || strcmp(t - 1, "noop: invalid service") == 0)) { - } else { + if(!((hostp->features == NULL) && (pkt->type == P_NAK) + && ((strcmp(t - 1, "unknown service: noop") == 0) + || (strcmp(t - 1, "noop: invalid service") == 0)))) { fprintf(outf, "ERROR: %s%s: %s\n", - (p->state == S_FAILED) ? "NAK " : "", - hostp->hostname, - t - 1); + (pkt->type == P_NAK) ? "NAK " : "", + hostp->hostname, + t - 1); remote_errors++; hostp->up = HOST_DONE; } @@ -1645,4 +1786,6 @@ pkt_t *pkt; } } start_host(hostp); + if(hostp->up == HOST_DONE) + security_close_connection(sech, hostp->hostname); }