X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=recover-src%2Famrecover.c;h=cf21c0312ce6553b6ef790a4eac6b6820ead003e;hb=12179dea039515c06168c0037d048566a3f623de;hp=1a54b1f8adbd49573ded0d0c00b4abfd0f9944fa;hpb=3ab887b9bc819a846c75dd7f2ee5d41fac22b19f;p=debian%2Famanda diff --git a/recover-src/amrecover.c b/recover-src/amrecover.c index 1a54b1f..cf21c03 100644 --- a/recover-src/amrecover.c +++ b/recover-src/amrecover.c @@ -24,53 +24,31 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: amrecover.c,v 1.29.4.7.4.6.2.7 2003/01/04 04:33:32 martinea Exp $ + * $Id: amrecover.c,v 1.73 2006/07/25 18:27:57 martinea Exp $ * * an interactive program for recovering backed-up files */ #include "amanda.h" #include "version.h" -#ifdef HAVE_NETINET_IN_SYSTM_H -#include -#endif -#include -#ifdef HAVE_NETINET_IP_H -#include -#endif #include "stream.h" #include "amfeatures.h" #include "amrecover.h" #include "getfsent.h" #include "dgram.h" - -#if defined(KRB4_SECURITY) -#include "krb4-security.h" -#endif #include "util.h" +#include "clientconf.h" +#include "protocol.h" +#include "event.h" +#include "security.h" -#ifdef HAVE_LIBREADLINE -# ifdef HAVE_READLINE_READLINE_H -# include -# ifdef HAVE_READLINE_HISTORY_H -# include -# endif -# else -# ifdef HAVE_READLINE_H -# include -# ifdef HAVE_HISTORY_H -# include -# endif -# else -# undef HAVE_LIBREADLINE -# endif -# endif -#endif - -extern int process_line P((char *line)); -int guess_disk P((char *cwd, size_t cwd_len, char **dn_guess, char **mpt_guess)); +extern int process_line(char *line); +int get_line(void); +int grab_reply(int show); +void sigint_handler(int signum); +int main(int argc, char **argv); -#define USAGE "Usage: amrecover [[-C] ] [-s ] [-t ] [-d ]\n" +#define USAGE "Usage: amrecover [[-C] ] [-s ] [-t ] [-d ] [-o ]*\n" char *config = NULL; char *server_name = NULL; @@ -87,79 +65,64 @@ char *tape_server_name = NULL; int tape_server_socket; char *tape_device_name = NULL; am_feature_t *our_features = NULL; -am_feature_t *their_features = NULL; - - -#ifndef HAVE_LIBREADLINE -/* - * simple readline() replacements - */ - -char * -readline(prompt) -char *prompt; -{ - printf("%s",prompt); - fflush(stdout); fflush(stderr); - return agets(stdin); -} - -#define add_history(x) /* add_history((x)) */ - -#endif - +char *our_features_string = NULL; +am_feature_t *indexsrv_features = NULL; +am_feature_t *tapesrv_features = NULL; +static char *errstr = NULL; +char *authopt; +int amindexd_alive = 0; + +static struct { + const char *name; + security_stream_t *fd; +} streams[] = { +#define MESGFD 0 + { "MESG", NULL }, +}; +#define NSTREAMS (int)(sizeof(streams) / sizeof(streams[0])) + +static void amindexd_response(void *, pkt_t *, security_handle_t *); +void stop_amindexd(void); +char *amindexd_client_get_security_conf(char *, void *); + +static char* mesg_buffer = NULL; /* gets a "line" from server and put in server_line */ /* server_line is terminated with \0, \r\n is striped */ /* returns -1 if error */ -int get_line () +int +get_line(void) { - char *line = NULL; - char *part = NULL; - size_t len; - - while(1) { - if((part = areads(server_socket)) == NULL) { - int save_errno = errno; - - if(server_line) { - fputs(server_line, stderr); /* show the last line read */ - fputc('\n', stderr); - } - if(save_errno != 0) { - fprintf(stderr, "%s: Error reading line from server: %s\n", - get_pname(), - strerror(save_errno)); - } else { - fprintf(stderr, "%s: Unexpected end of file, check amindexd*debug on server %s\n", - get_pname(), - server_name); - } - amfree(line); - amfree(server_line); - errno = save_errno; + ssize_t size; + char *newbuf, *s; + void *buf; + + if (!mesg_buffer) + mesg_buffer = stralloc(""); + + while (!strstr(mesg_buffer,"\r\n")) { + size = security_stream_read_sync(streams[MESGFD].fd, &buf); + if(size < 0) { return -1; } - if(line) { - strappend(line, part); - amfree(part); - } else { - line = part; - part = NULL; - } - if((len = strlen(line)) > 0 && line[len-1] == '\r') { - line[len-1] = '\0'; - server_line = newstralloc(server_line, line); - amfree(line); - return 0; + else if(size == 0) { + return -1; } - /* - * Hmmm. We got a "line" from areads(), which means it saw - * a '\n' (or EOF, etc), but there was not a '\r' before it. - * Put a '\n' back in the buffer and loop for more. - */ - strappend(line, "\n"); + newbuf = alloc(strlen(mesg_buffer)+size+1); + strncpy(newbuf, mesg_buffer, (size_t)(strlen(mesg_buffer) + size)); + memcpy(newbuf+strlen(mesg_buffer), buf, (size_t)size); + newbuf[strlen(mesg_buffer)+size] = '\0'; + amfree(mesg_buffer); + mesg_buffer = newbuf; } + + s = strstr(mesg_buffer,"\r\n"); + *s = '\0'; + newbuf = stralloc(s+2); + server_line = newstralloc(server_line, mesg_buffer); + amfree(mesg_buffer); + mesg_buffer = newbuf; + return 0; } @@ -168,8 +131,9 @@ int get_line () /* return -1 if error */ /* return code returned by server always occupies first 3 bytes of global variable server_line */ -int grab_reply (show) -int show; +int +grab_reply( + int show) { do { if (get_line() == -1) { @@ -185,7 +149,8 @@ int show; /* get 1 line of reply */ /* returns -1 if error, 0 if last (or only) line, 1 if more to follow */ -int get_reply_line () +int +get_reply_line(void) { if (get_line() == -1) return -1; @@ -194,7 +159,8 @@ int get_reply_line () /* returns pointer to returned line */ -char *reply_line () +char * +reply_line(void) { return server_line; } @@ -203,43 +169,43 @@ char *reply_line () /* returns 0 if server returned an error code (ie code starting with 5) and non-zero otherwise */ -int server_happy () +int +server_happy(void) { return server_line[0] != '5'; } -int send_command(cmd) -char *cmd; +int +send_command( + char * cmd) { - size_t l, n; - ssize_t s; - char *end; - /* * NOTE: this routine is called from sigint_handler, so we must be * **very** careful about what we do since there is no way to know * our state at the time the interrupt happened. For instance, - * do not use any stdio routines here. + * do not use any stdio or malloc routines here. */ - for (l = 0, n = strlen(cmd); l < n; l += s) - if ((s = write(server_socket, cmd + l, n - l)) < 0) { - perror("amrecover: Error writing to server"); - return -1; - } - end = "\r\n"; - for (l = 0, n = strlen(end); l < n; l += s) - if ((s = write(server_socket, end + l, n - l)) < 0) { - perror("amrecover: Error writing to server"); - return -1; - } - return 0; + char *buffer; + + buffer = alloc(strlen(cmd)+3); + strncpy(buffer, cmd, strlen(cmd)); + buffer[strlen(cmd)] = '\r'; + buffer[strlen(cmd)+1] = '\n'; + buffer[strlen(cmd)+2] = '\0'; + + if(security_stream_write(streams[MESGFD].fd, buffer, strlen(buffer)) < 0) { + return -1; + } + amfree(buffer); + return (0); } /* send a command to the server, get reply and print to screen */ -int converse(cmd) -char *cmd; +int +converse( + char * cmd) { if (send_command(cmd) == -1) return -1; if (grab_reply(1) == -1) return -1; @@ -248,8 +214,9 @@ char *cmd; /* same as converse() but reply not echoed to stdout */ -int exchange(cmd) -char *cmd; +int +exchange( + char * cmd) { if (send_command(cmd) == -1) return -1; if (grab_reply(0) == -1) return -1; @@ -259,8 +226,9 @@ char *cmd; /* basic interrupt handler for when user presses ^C */ /* Bale out, letting server know before doing so */ -void sigint_handler(signum) -int signum; +void +sigint_handler( + int signum) { /* * NOTE: we must be **very** careful about what we do here since there @@ -269,17 +237,22 @@ int signum; * routines. Also, use _exit() instead of exit() to make sure stdio * buffer flushing is not attempted. */ + (void)signum; /* Quiet unused parameter warning */ + if (extract_restore_child_pid != -1) (void)kill(extract_restore_child_pid, SIGKILL); extract_restore_child_pid = -1; - (void)send_command("QUIT"); + if(amindexd_alive) + (void)send_command("QUIT"); + _exit(1); } -void clean_pathname(s) -char *s; +void +clean_pathname( + char * s) { size_t length; length = strlen(s); @@ -298,205 +271,107 @@ char *s; } -/* try and guess the disk the user is currently on. - Return -1 if error, 0 if disk not local, 1 if disk local, - 2 if disk local but can't guess name */ -/* do this by looking for the longest mount point which matches the - current directory */ -int guess_disk (cwd, cwd_len, dn_guess, mpt_guess) - char *cwd, **dn_guess, **mpt_guess; - size_t cwd_len; -{ - size_t longest_match = 0; - size_t current_length; - size_t cwd_length; - int local_disk = 0; - generic_fsent_t fsent; - char *fsname = NULL; - char *disk_try = NULL; - - *dn_guess = *mpt_guess = NULL; - - if (getcwd(cwd, cwd_len) == NULL) - return -1; - cwd_length = strlen(cwd); - dbprintf(("guess_disk: %d: \"%s\"\n", cwd_length, cwd)); - - if (open_fstab() == 0) - return -1; - - while (get_fstab_nextentry(&fsent)) - { - current_length = fsent.mntdir ? strlen(fsent.mntdir) : (size_t)0; - dbprintf(("guess_disk: %d: %d: \"%s\": \"%s\"\n", - longest_match, - current_length, - fsent.mntdir ? fsent.mntdir : "(mntdir null)", - fsent.fsname ? fsent.fsname : "(fsname null)")); - if ((current_length > longest_match) - && (current_length <= cwd_length) - && (strncmp(fsent.mntdir, cwd, current_length) == 0)) - { - longest_match = current_length; - amfree(*mpt_guess); - *mpt_guess = stralloc(fsent.mntdir); - if(strncmp(fsent.fsname,DEV_PREFIX,(strlen(DEV_PREFIX)))) - { - fsname = newstralloc(fsname, fsent.fsname); - } - else - { - fsname = newstralloc(fsname,fsent.fsname+strlen(DEV_PREFIX)); - } - local_disk = is_local_fstype(&fsent); - dbprintf(("guess_disk: local_disk = %d, fsname = \"%s\"\n", - local_disk, - fsname)); - } - } - close_fstab(); - - if (longest_match == 0) { - amfree(*mpt_guess); - amfree(fsname); - return -1; /* ? at least / should match */ - } - - if (!local_disk) { - amfree(*mpt_guess); - amfree(fsname); - return 0; - } - - /* have mount point now */ - /* disk name may be specified by mount point (logical name) or - device name, have to determine */ - printf("Trying disk %s ...\n", *mpt_guess); - disk_try = stralloc2("DISK ", *mpt_guess); /* try logical name */ - if (exchange(disk_try) == -1) - exit(1); - amfree(disk_try); - if (server_happy()) - { - *dn_guess = stralloc(*mpt_guess); /* logical is okay */ - amfree(fsname); - return 1; - } - printf("Trying disk %s ...\n", fsname); - disk_try = stralloc2("DISK ", fsname); /* try device name */ - if (exchange(disk_try) == -1) - exit(1); - amfree(disk_try); - if (server_happy()) - { - *dn_guess = stralloc(fsname); /* dev name is okay */ - amfree(fsname); - return 1; - } - - /* neither is okay */ - amfree(*mpt_guess); - amfree(fsname); - return 2; -} - - -void quit () +void +quit(void) { quit_prog = 1; (void)converse("QUIT"); + stop_amindexd(); } char *localhost = NULL; -int main(argc, argv) -int argc; -char **argv; +#ifdef DEFAULT_TAPE_SERVER +# define DEFAULT_TAPE_SERVER_FAILOVER (DEFAULT_TAPE_SERVER) +#else +# define DEFAULT_TAPE_SERVER_FAILOVER (NULL) +#endif + +int +main( + int argc, + char ** argv) { - int my_port; - struct servent *sp; int i; time_t timer; char *lineread = NULL; struct sigaction act, oact; extern char *optarg; extern int optind; - char cwd[STR_SIZE], *dn_guess = NULL, *mpt_guess = NULL; - char *service_name; char *line = NULL; - int fd; + char *conffile; + const security_driver_t *secdrv; + char *req = NULL; + int response_error; + int new_argc; + char **new_argv; + struct tm *tm; - 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); set_pname("amrecover"); - dbopen(); + + /* Don't die when child closes pipe */ + signal(SIGPIPE, SIG_IGN); + + dbopen(DBG_SUBDIR_CLIENT); #ifndef IGNORE_UID_CHECK if (geteuid() != 0) { erroutput_type |= ERR_SYSLOG; error("amrecover must be run by root"); + /*NOTREACHED*/ } #endif localhost = alloc(MAX_HOSTNAME_LENGTH+1); if (gethostname(localhost, MAX_HOSTNAME_LENGTH) != 0) { error("cannot determine local host name\n"); + /*NOTREACHED*/ } localhost[MAX_HOSTNAME_LENGTH] = '\0'; - config = newstralloc(config, DEFAULT_CONFIG); - server_name = newstralloc(server_name, DEFAULT_SERVER); -#ifdef DEFAULT_TAPE_SERVER - tape_server_name = newstralloc(tape_server_name, DEFAULT_TAPE_SERVER); -#else - amfree(tape_server_name); -#endif - if (argc > 1 && argv[1][0] != '-') - { + parse_client_conf(argc, argv, &new_argc, &new_argv); + + if (new_argc > 1 && new_argv[1][0] != '-') { /* * If the first argument is not an option flag, then we assume * it is a configuration name to match the syntax of the other * Amanda utilities. */ - char **new_argv; + char **new_argv1; - new_argv = (char **) alloc ((argc + 1 + 1) * sizeof (*new_argv)); - new_argv[0] = argv[0]; - new_argv[1] = "-C"; - for (i = 1; i < argc; i++) - { - new_argv[i + 1] = argv[i]; + new_argv1 = (char **) alloc((size_t)((new_argc + 1 + 1) * sizeof(*new_argv1))); + new_argv1[0] = new_argv[0]; + new_argv1[1] = "-C"; + for (i = 1; i < new_argc; i++) { + new_argv1[i + 1] = new_argv[i]; } - new_argv[i + 1] = NULL; - argc++; - argv = new_argv; + new_argv1[i + 1] = NULL; + new_argc++; + amfree(new_argv); + new_argv = new_argv1; } - while ((i = getopt(argc, argv, "C:s:t:d:U")) != EOF) - { - switch (i) - { + while ((i = getopt(new_argc, new_argv, "C:s:t:d:U")) != EOF) { + switch (i) { case 'C': - config = newstralloc(config, optarg); + add_client_conf(CLN_CONF, optarg); + //config = newstralloc(config, optarg); break; case 's': - server_name = newstralloc(server_name, optarg); + add_client_conf(CLN_INDEX_SERVER, optarg); + //server_name = newstralloc(server_name, optarg); break; case 't': - tape_server_name = newstralloc(tape_server_name, optarg); + add_client_conf(CLN_TAPE_SERVER, optarg); + //tape_server_name = newstralloc(tape_server_name, optarg); break; case 'd': - tape_device_name = newstralloc(tape_device_name, optarg); + add_client_conf(CLN_TAPEDEV, optarg); + //tape_device_name = newstralloc(tape_device_name, optarg); break; case 'U': @@ -505,47 +380,99 @@ char **argv; return 0; } } - if (optind != argc) - { + if (optind != new_argc) { (void)fprintf(stderr, USAGE); exit(1); } + our_features = am_init_feature_set(); + our_features_string = am_feature_to_string(our_features); + + conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL); + if (read_clientconf(conffile) > 0) { + error("error reading conffile: %s", conffile); + /*NOTREACHED*/ + } + amfree(conffile); + + config = stralloc(client_getconf_str(CLN_CONF)); + + conffile = vstralloc(CONFIG_DIR, "/", config, "/", "amanda-client.conf", + NULL); + if (read_clientconf(conffile) > 0) { + error("error reading conffile: %s", conffile); + /*NOTREACHED*/ + } + amfree(conffile); + + dbrename(config, DBG_SUBDIR_CLIENT); + + report_bad_client_arg(); + + amfree(server_name); + server_name = getenv("AMANDA_SERVER"); + if(!server_name) server_name = client_getconf_str(CLN_INDEX_SERVER); + server_name = stralloc(server_name); + + amfree(tape_server_name); + tape_server_name = getenv("AMANDA_TAPESERVER"); + if(!tape_server_name) tape_server_name = client_getconf_str(CLN_TAPE_SERVER); + tape_server_name = stralloc(tape_server_name); + + amfree(tape_device_name); + tape_device_name = client_getconf_str(CLN_TAPEDEV); + if (tape_device_name) + tape_device_name = stralloc(tape_device_name); + + authopt = stralloc(client_getconf_str(CLN_AUTH)); + + amfree(disk_name); amfree(mount_point); amfree(disk_path); dump_date[0] = '\0'; + /* Don't die when child closes pipe */ + signal(SIGPIPE, SIG_IGN); + /* set up signal handler */ act.sa_handler = sigint_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; - if (sigaction(SIGINT, &act, &oact) != 0) - { + if (sigaction(SIGINT, &act, &oact) != 0) { error("error setting signal handler: %s", strerror(errno)); + /*NOTREACHED*/ } - service_name = stralloc2("amandaidx", SERVICE_SUFFIX); + protocol_init(); + + /* We assume that amindexd support fe_amindexd_options_features */ + /* and fe_amindexd_options_auth */ + /* We should send a noop to really know */ + req = vstralloc("SERVICE amindexd\n", + "OPTIONS ", "features=", our_features_string, ";", + "auth=", authopt, ";", + "\n", NULL); + + secdrv = security_getdriver(authopt); + if (secdrv == NULL) { + error("no '%s' security driver available for host '%s'", + authopt, server_name); + /*NOTREACHED*/ + } + + protocol_sendreq(server_name, secdrv, amindexd_client_get_security_conf, + req, STARTUP_TIMEOUT, amindexd_response, &response_error); + + amfree(req); + protocol_run(); printf("AMRECOVER Version %s. Contacting server on %s ...\n", - version(), server_name); - if ((sp = getservbyname(service_name, "tcp")) == NULL) - { - error("%s/tcp unknown protocol", service_name); - } - amfree(service_name); - server_socket = stream_client_privileged(server_name, - ntohs(sp->s_port), - -1, - -1, - &my_port); - if (server_socket < 0) - { - error("cannot connect to %s: %s", server_name, strerror(errno)); - } - if (my_port >= IPPORT_RESERVED) - { - error("did not get a reserved port: %d", my_port); + version(), server_name); + + if(response_error != 0) { + fprintf(stderr,"%s\n",errstr); + exit(1); } #if 0 @@ -559,113 +486,68 @@ char **argv; #endif /* get server's banner */ - if (grab_reply(1) == -1) + if (grab_reply(1) == -1) { + aclose(server_socket); exit(1); - if (!server_happy()) - { + } + if (!server_happy()) { dbclose(); aclose(server_socket); exit(1); } - /* do the security thing */ -#if defined(KRB4_SECURITY) -#if 0 /* not yet implemented */ - if(krb4_auth) - { - line = get_krb_security(); - } else -#endif /* 0 */ -#endif - { - line = get_bsd_security(); - } - if (converse(line) == -1) - exit(1); - if (!server_happy()) - exit(1); - memset(line, '\0', strlen(line)); - amfree(line); - - /* try to get the features form the server */ + /* try to get the features from the server */ { - char *our_feature_string = NULL; char *their_feature_string = NULL; - our_features = am_init_feature_set(); - our_feature_string = am_feature_to_string(our_features); - line = stralloc2("FEATURES ", our_feature_string); + line = stralloc2("FEATURES ", our_features_string); if(exchange(line) == 0) { their_feature_string = stralloc(server_line+13); - their_features = am_string_to_feature(their_feature_string); + indexsrv_features = am_string_to_feature(their_feature_string); } else { - their_features = am_set_default_feature_set(); + indexsrv_features = am_set_default_feature_set(); } - amfree(our_feature_string); amfree(their_feature_string); amfree(line); } /* set the date of extraction to be today */ (void)time(&timer); - strftime(dump_date, sizeof(dump_date), "%Y-%m-%d", localtime(&timer)); + tm = localtime(&timer); + if (tm) + strftime(dump_date, sizeof(dump_date), "%Y-%m-%d", tm); + else + error("BAD DATE"); + printf("Setting restore date to today (%s)\n", dump_date); line = stralloc2("DATE ", dump_date); - if (converse(line) == -1) + if (converse(line) == -1) { + aclose(server_socket); exit(1); + } amfree(line); line = stralloc2("SCNF ", config); - if (converse(line) == -1) + if (converse(line) == -1) { + aclose(server_socket); exit(1); + } amfree(line); - if (server_happy()) - { + if (server_happy()) { /* set host we are restoring to this host by default */ amfree(dump_hostname); set_host(localhost); if (dump_hostname) - { - /* get a starting disk and directory based on where - we currently are */ - switch (guess_disk(cwd, sizeof(cwd), &dn_guess, &mpt_guess)) - { - case 1: - /* okay, got a guess. Set disk accordingly */ - printf("$CWD '%s' is on disk '%s' mounted at '%s'.\n", - cwd, dn_guess, mpt_guess); - set_disk(dn_guess, mpt_guess); - set_directory(cwd); - if (server_happy() && strcmp(cwd, mpt_guess) != 0) - printf("WARNING: not on root of selected filesystem, check man-page!\n"); - amfree(dn_guess); - amfree(mpt_guess); - break; - - case 0: - printf("$CWD '%s' is on a network mounted disk\n", - cwd); - printf("so you must 'sethost' to the server\n"); - /* fake an unhappy server */ - server_line[0] = '5'; - break; - - case 2: - case -1: - default: - printf("Can't determine disk and mount point from $CWD '%s'\n", cwd); - /* fake an unhappy server */ - server_line[0] = '5'; - break; - } - } + printf("Use the setdisk command to choose dump disk to recover\n"); + else + printf("Use the sethost command to choose a host to recover\n"); + } quit_prog = 0; - do - { + do { if ((lineread = readline("amrecover> ")) == NULL) { clearerr(stdin); putchar('\n'); @@ -684,3 +566,246 @@ char **argv; aclose(server_socket); return 0; } + +static void +amindexd_response( + void *datap, + pkt_t *pkt, + security_handle_t *sech) +{ + int ports[NSTREAMS], *response_error = datap, i; + char *p; + char *tok; + char *extra = NULL; + + assert(response_error != NULL); + assert(sech != NULL); + + if (pkt == NULL) { + errstr = newvstralloc(errstr, "[request failed: ", + security_geterror(sech), "]", NULL); + *response_error = 1; + return; + } + + if (pkt->type == P_NAK) { +#if defined(PACKET_DEBUG) + fprintf(stderr, "got nak response:\n----\n%s\n----\n\n", pkt->body); +#endif + + tok = strtok(pkt->body, " "); + if (tok == NULL || strcmp(tok, "ERROR") != 0) + goto bad_nak; + + tok = strtok(NULL, "\n"); + if (tok != NULL) { + errstr = newvstralloc(errstr, "NAK: ", tok, NULL); + *response_error = 1; + } else { +bad_nak: + errstr = newstralloc(errstr, "request NAK"); + *response_error = 2; + } + return; + } + + if (pkt->type != P_REP) { + errstr = newvstralloc(errstr, "received strange packet type ", + pkt_type2str(pkt->type), ": ", pkt->body, NULL); + *response_error = 1; + return; + } + +#if defined(PACKET_DEBUG) + fprintf(stderr, "got response:\n----\n%s\n----\n\n", pkt->body); +#endif + + for(i = 0; i < NSTREAMS; i++) { + ports[i] = -1; + streams[i].fd = NULL; + } + + p = pkt->body; + while((tok = strtok(p, " \n")) != NULL) { + p = NULL; + + /* + * Error response packets have "ERROR" followed by the error message + * followed by a newline. + */ + if (strcmp(tok, "ERROR") == 0) { + tok = strtok(NULL, "\n"); + if (tok == NULL) + tok = "[bogus error packet]"; + errstr = newstralloc(errstr, tok); + *response_error = 2; + return; + } + + + /* + * Regular packets have CONNECT followed by three streams + */ + if (strcmp(tok, "CONNECT") == 0) { + + /* + * Parse the three stream specifiers out of the packet. + */ + for (i = 0; i < NSTREAMS; i++) { + tok = strtok(NULL, " "); + if (tok == NULL || strcmp(tok, streams[i].name) != 0) { + extra = vstralloc("CONNECT token is \"", + tok ? tok : "(null)", + "\": expected \"", + streams[i].name, + "\"", + NULL); + goto parse_error; + } + tok = strtok(NULL, " \n"); + if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) { + extra = vstralloc("CONNECT ", + streams[i].name, + " token is \"", + tok ? tok : "(null)", + "\": expected a port number", + NULL); + goto parse_error; + } + } + continue; + } + + /* + * OPTIONS [options string] '\n' + */ + if (strcmp(tok, "OPTIONS") == 0) { + tok = strtok(NULL, "\n"); + if (tok == NULL) { + extra = stralloc("OPTIONS token is missing"); + goto parse_error; + } +/* + tok_end = tok + strlen(tok); + while((p = strchr(tok, ';')) != NULL) { + *p++ = '\0'; +#define sc "features=" + if(strncmp(tok, sc, sizeof(sc)-1) == 0) { + tok += sizeof(sc) - 1; +#undef sc + am_release_feature_set(their_features); + if((their_features = am_string_to_feature(tok)) == NULL) { + errstr = newvstralloc(errstr, + "OPTIONS: bad features value: ", + tok, + NULL); + goto parse_error; + } + } + tok = p; + } +*/ + continue; + } +/* + extra = vstralloc("next token is \"", + tok ? tok : "(null)", + "\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\"", + NULL); + goto parse_error; +*/ + } + + /* + * Connect the streams to their remote ports + */ + for (i = 0; i < NSTREAMS; i++) { +/*@i@*/ if (ports[i] == -1) + continue; + streams[i].fd = security_stream_client(sech, ports[i]); + if (streams[i].fd == NULL) { + errstr = newvstralloc(errstr, + "[could not connect ", streams[i].name, " stream: ", + security_geterror(sech), "]", NULL); + goto connect_error; + } + } + /* + * Authenticate the streams + */ + for (i = 0; i < NSTREAMS; i++) { + if (streams[i].fd == NULL) + continue; + if (security_stream_auth(streams[i].fd) < 0) { + errstr = newvstralloc(errstr, + "[could not authenticate ", streams[i].name, " stream: ", + security_stream_geterror(streams[i].fd), "]", NULL); + goto connect_error; + } + } + + /* + * The MESGFD and DATAFD streams are mandatory. If we didn't get + * them, complain. + */ + if (streams[MESGFD].fd == NULL) { + errstr = newstralloc(errstr, "[couldn't open MESG streams]"); + goto connect_error; + } + + /* everything worked */ + *response_error = 0; + amindexd_alive = 1; + return; + +parse_error: + errstr = newvstralloc(errstr, + "[parse of reply message failed: ", + extra ? extra : "(no additional information)", + "]", + NULL); + amfree(extra); + *response_error = 2; + return; + +connect_error: + stop_amindexd(); + *response_error = 1; +} + +/* + * This is called when everything needs to shut down so event_loop() + * will exit. + */ +void +stop_amindexd(void) +{ + int i; + + amindexd_alive = 0; + for (i = 0; i < NSTREAMS; i++) { + if (streams[i].fd != NULL) { + security_stream_close(streams[i].fd); + streams[i].fd = NULL; + } + } +} + +char * +amindexd_client_get_security_conf( + char * string, + void * arg) +{ + (void)arg; /* Quiet unused parameter warning */ + + if(!string || !*string) + return(NULL); + + if(strcmp(string, "auth")==0) { + return(client_getconf_str(CLN_AUTH)); + } + else if(strcmp(string, "ssh_keys")==0) { + return(client_getconf_str(CLN_SSH_KEYS)); + } + return(NULL); +}