X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Famservice.c;fp=common-src%2Famservice.c;h=286a77059ad103b63cb82c33a57d682c7a993966;hb=cd0b924f27312d57bd42f6c4fae2b795139e2d0b;hp=0000000000000000000000000000000000000000;hpb=011a59f5a54864108a16af570a6b287410597cc2;p=debian%2Famanda diff --git a/common-src/amservice.c b/common-src/amservice.c new file mode 100644 index 0000000..286a770 --- /dev/null +++ b/common-src/amservice.c @@ -0,0 +1,348 @@ +/* + * Amanda, The Advanced Maryland Automatic Network Disk Archiver + * Copyright (c) 1991-2000 University of Maryland at College Park + * All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of U.M. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. U.M. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: the Amanda Development Team. Its members are listed in a + * file named AUTHORS, in the root directory of this distribution. + */ +/* + * $Id: amservice.c 11167 2008-05-06 11:53:54Z martineau $ + * + * Take the REQ packet in stdin and output the REP packet in stdout + */ +#include "amanda.h" +#include "util.h" +#include "conffile.h" +#include "packet.h" +#include "protocol.h" +#include "amfeatures.h" +#include "event.h" + +static int copy_stream = 0; +static time_t conf_ctimeout; +static am_feature_t *our_features = NULL; +static char *our_feature_string = NULL; +static int remote_errors = 0; +static event_handle_t *event_in; +static security_stream_t *fd; + +/* local functions */ + +void usage(void); +void client_protocol(char *hostname, char *auth, char *service, + FILE *input_file); +void client_first_stream(security_handle_t *sech, int port_num); +int main(int argc, char **argv); +static void read_in(void *cookie); +void aaa(void); +static void read_server(void *cookie, void *buf, ssize_t size); + +void +usage(void) +{ + error(_("Usage: amservice [-o configoption]* [-f input_file [-s]] host auth service")); + /*NOTREACHED*/ +} + +int +main( + int argc, + char ** argv) +{ + config_overrides_t *cfg_ovr; + char *hostname; + char *auth; + char *service; + int opt; + extern int optind; + extern char *optarg; + FILE *input_file; + int use_connect = 0; + int got_input_file = 0; + + /* + * Configure program for internationalization: + * 1) Only set the message locale for now. + * 2) Set textdomain for all amanda related programs to "amanda" + * We don't want to be forced to support dozens of message catalogs. + */ + setlocale(LC_MESSAGES, "C"); + textdomain("amanda"); + + safe_fd(-1, 0); + safe_cd(); + + set_pname("amservice"); + /* drop root privileges */ + if (!set_root_privs(0)) { + error(_("amservice must be run setuid root")); + } + + /* Don't die when child closes pipe */ + signal(SIGPIPE, SIG_IGN); + + dbopen(DBG_SUBDIR_SERVER); + + add_amanda_log_handler(amanda_log_stderr); + + our_features = am_init_feature_set(); + our_feature_string = am_feature_to_string(our_features); + + /* process arguments */ + + cfg_ovr = new_config_overrides(argc/2); + input_file = stdin; + while((opt = getopt(argc, argv, "o:f:s")) != EOF) { + switch(opt) { + case 'o': add_config_override_opt(cfg_ovr, optarg); + break; + case 'f': got_input_file = 1; + if (*optarg == '/') { + input_file = fopen(optarg, "r"); + } else { + char *name = vstralloc(get_original_cwd(), "/", + optarg, NULL); + input_file = fopen(name, "r"); + amfree(name); + } + if (!input_file) + g_critical("Cannot open output file '%s': %s", + optarg, strerror(errno)); + break; + case 's': use_connect = 1; + break; + } + } + + if (use_connect && !got_input_file) { + g_critical("The -s option require -f"); + } + + argc -= optind, argv += optind; + if(argc < 3) usage(); + + /* set a default config */ + set_config_overrides(cfg_ovr); + config_init(CONFIG_INIT_CLIENT, NULL); + dbrename(get_config_name(), DBG_SUBDIR_SERVER); + + if (config_errors(NULL) >= CFGERR_WARNINGS) { + config_print_errors(); + if (config_errors(NULL) >= CFGERR_ERRORS) { + g_critical(_("errors processing config file")); + } + } + + conf_ctimeout = (time_t)getconf_int(CNF_CTIMEOUT); + + hostname = argv[0]; + auth = argv[1]; + service = argv[2]; + + /* start client side checks */ + + copy_stream = use_connect && got_input_file; + client_protocol(hostname, auth, service, input_file); + + amfree(our_feature_string); + am_release_feature_set(our_features); + our_features = NULL; + + dbclose(); + return(remote_errors != 0); +} + +/* --------------------------------------------------- */ + +static void handle_result(void *, pkt_t *, security_handle_t *); +void start_host(char *hostname, char *auth, char *req); + +void +start_host( + char *hostname, + char *auth, + char *req) +{ + const security_driver_t *secdrv; + secdrv = security_getdriver(auth); + if (secdrv == NULL) { + fprintf(stderr, _("Could not find security driver \"%s\".\n"), auth); + } else { + protocol_sendreq(hostname, secdrv, generic_client_get_security_conf, + req, conf_ctimeout, handle_result, NULL); + } + +} + +void +client_protocol( + char *hostname, + char *auth, + char *service, + FILE *input_file) +{ + char *req, *req1; + + req = g_strdup_printf("SERVICE %s\nOPTIONS features=%s\n", + service, our_feature_string); + req1 = malloc(1024); + while(fgets(req1, 1024, input_file) != NULL) { + vstrextend(&req, req1, NULL); + } + protocol_init(); + + start_host(hostname, auth, req); + + protocol_run(); + + fflush(stdout); + + amfree(our_feature_string); + + return; +} + +static void +handle_result( + void *datap G_GNUC_UNUSED, + pkt_t *pkt, + security_handle_t *sech) +{ + char *line; + char *s; + int ch; + int port_num = 0; + int has_error = 0; + + if (pkt == NULL) { + g_fprintf(stdout, + _("Request failed: %s\n"), security_geterror(sech)); + remote_errors++; + return; + } + + s = pkt->body; + ch = *s++; + while(ch) { + line = s - 1; + skip_quoted_line(s, ch); + if (s[-2] == '\n') { + s[-2] = '\0'; + } + + if (copy_stream) { + g_debug("REP: %s\n", line); + } else { + fprintf(stdout, "%s\n", line); + } + if (strncmp(line, "CONNECT ", 8) == 0) { + char *port = strchr(line, ' '); + if (port) { + port = strchr(port+1, ' '); + if (port) { + port_num = atoi(port+1); + } + } + } else if (strncmp(line, "ERROR ", 6) == 0) { + if (copy_stream) { + fprintf(stdout, "%s\n", line); + } + has_error++; + } + } + + if (has_error) + return; + + if (copy_stream) { + client_first_stream(sech, port_num); + } else { + fprintf(stdout, "\n"); + } + +} + +void +client_first_stream( + security_handle_t *sech, + int port_num) +{ + + if (port_num == 0) { + g_critical("The service did not ask to open stream, do not use '-s' with that service"); + } + + fd = security_stream_client(sech, port_num); + if (!fd) { + g_critical("Could not connect to stream: %s\n", security_stream_geterror(fd)); + } + if (security_stream_auth(fd) < 0) { + g_critical("could not authenticate stream: %s\n", security_stream_geterror(fd)); + } + + printf("Connected\n"); + /* read from stdin */ + event_in = event_register((event_id_t)0, EV_READFD, read_in, NULL); + + /* read from connected stream */ + security_stream_read(fd, read_server, NULL); +} + + +static void +read_in( + void *cookie G_GNUC_UNUSED) +{ + size_t nread; + char buf[1024]; + + event_release(event_in); + nread = read(0, buf, 1024); + if (nread == 0) { + security_stream_close(fd); + return; + } + + buf[nread] = '\0'; + security_stream_write(fd, buf, nread); + event_in = event_register((event_id_t)0, EV_READFD, read_in, NULL); +} + +static void +read_server( + void * cookie G_GNUC_UNUSED, + void * buf, + ssize_t size) +{ + switch (size) { + case -1: + case 0: security_stream_close(fd); + event_release(event_in); + break; + default: + full_write(1, buf, size); + if (errno > 0) { + g_debug("failed to write to stdout: %s", strerror(errno)); + } + security_stream_read(fd, read_server, NULL); + break; + } +}