⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 amandad.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1999 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: amandad.c,v 1.18 2006/08/21 20:17:09 martinea Exp $ * * handle client-host side of Amanda network communications, including * security checks, execution of the proper service, and acking the * master side */#include "amanda.h"#include "amandad.h"#include "clock.h"#include "event.h"#include "amfeatures.h"#include "packet.h"#include "version.h"#include "queue.h"#include "security.h"#include "stream.h"#include "util.h"#include "conffile.h"#define	REP_TIMEOUT	(6*60*60)	/* secs for service to reply */#define	ACK_TIMEOUT  	10		/* XXX should be configurable */#define amandad_debug(i, ...) do {	\	if ((i) <= debug_amandad) {	\		dbprintf(__VA_ARGS__);	\	}				\} while (0)/* * These are the actions for entering the state machine */typedef enum { A_START, A_RECVPKT, A_RECVREP, A_PENDING, A_FINISH, A_CONTINUE,    A_SENDNAK, A_TIMEOUT } action_t;/* * This is a state in the state machine.  It is a function pointer to * the function that actually implements the state. */struct active_service;typedef action_t (*state_t)(struct active_service *, action_t, pkt_t *);/* * This structure describes an active running service. * * An active service is something running that we have received * a request for.  This structure holds info on that service, including * file descriptors for data, etc, as well as the security handle * for communications with the amanda server. */struct active_service {    char *cmd;				/* name of command we ran */    char *arguments;			/* arguments we sent it */    security_handle_t *security_handle;	/* remote server */    state_t state;			/* how far this has progressed */    pid_t pid;				/* pid of subprocess */    int send_partial_reply;		/* send PREP packet */    int reqfd;				/* pipe to write requests */    int repfd;				/* pipe to read replies */    event_handle_t *ev_repfd;		/* read event handle for repfd */    event_handle_t *ev_reptimeout;	/* timeout for rep data */    pkt_t rep_pkt;			/* rep packet we're sending out */    char *repbuf;			/* buffer to read the rep into */    size_t bufsize;			/* length of repbuf */    size_t repbufsize;			/* length of repbuf */    int repretry;			/* times we'll retry sending the rep */    /*     * General user streams to the process, and their equivalent     * network streams.     */    struct datafd_handle {	int fd_read;			/* pipe to child process */	int fd_write;			/* pipe to child process */	event_handle_t *ev_read;	/* it's read event handle */	event_handle_t *ev_write;	/* it's write event handle */	security_stream_t *netfd;	/* stream to amanda server */	struct active_service *as;	/* pointer back to our enclosure */    } data[DATA_FD_COUNT];    char databuf[NETWORK_BLOCK_BYTES];	/* buffer to relay netfd data in */    TAILQ_ENTRY(active_service) tq;	/* queue handle */};/*  * Here are the services that we allow. */static struct services {    char *name;    int  active;} services[] = {    { "noop", 1 },    { "sendsize", 1 },    { "sendbackup", 1 },    { "selfcheck", 1 },    { "amindexd", 0 },    { "amidxtaped", 0 }};#define	NSERVICES	(int)(sizeof(services) / sizeof(services[0]))/* * Queue of outstanding requests that we are running. */static struct {    TAILQ_HEAD(, active_service) tailq;    int qlength;} serviceq = {    TAILQ_HEAD_INITIALIZER(serviceq.tailq), 0};static int wait_30s = 1;static int exit_on_qlength = 1;static char *auth = NULL;static kencrypt_type amandad_kencrypt = KENCRYPT_NONE;int main(int argc, char **argv);static int allocstream(struct active_service *, int);static void exit_check(void *);static void protocol_accept(security_handle_t *, pkt_t *);static void state_machine(struct active_service *, action_t, pkt_t *);static action_t s_sendack(struct active_service *, action_t, pkt_t *);static action_t s_repwait(struct active_service *, action_t, pkt_t *);static action_t s_processrep(struct active_service *, action_t, pkt_t *);static action_t s_sendrep(struct active_service *, action_t, pkt_t *);static action_t s_ackwait(struct active_service *, action_t, pkt_t *);static void repfd_recv(void *);static void timeout_repfd(void *);static void protocol_recv(void *, pkt_t *, security_status_t);static void process_readnetfd(void *);static void process_writenetfd(void *, void *, ssize_t);static struct active_service *service_new(security_handle_t *,    const char *, const char *);static void service_delete(struct active_service *);static int writebuf(struct active_service *, const void *, size_t);static ssize_t do_sendpkt(security_handle_t *handle, pkt_t *pkt);static char *amandad_get_security_conf (char *, void *);static const char *state2str(state_t);static const char *action2str(action_t);intmain(    int		argc,    char **	argv){    int i, j;    int have_services;    int in, out;    const security_driver_t *secdrv;    int no_exit = 0;    char *pgm = "amandad";		/* in case argv[0] is not set */#if defined(USE_REUSEADDR)    const int on = 1;    int r;#endif    /*     * 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();    /*     * When called via inetd, it is not uncommon to forget to put the     * argv[0] value on the config line.  On some systems (e.g. Solaris)     * this causes argv and/or argv[0] to be NULL, so we have to be     * careful getting our name.     */    if ((argv == NULL) || (argv[0] == NULL)) {	    pgm = "amandad";		/* in case argv[0] is not set */    } else {	    pgm = basename(argv[0]);	/* Strip of leading path get debug name */    }    set_pname(pgm);    dbopen(DBG_SUBDIR_AMANDAD);    if(argv == NULL) {	error(_("argv == NULL\n"));	/*NOTREACHED*/    }    /* Don't die when child closes pipe */    signal(SIGPIPE, SIG_IGN);    config_init(CONFIG_INIT_CLIENT, NULL);    check_running_as(RUNNING_AS_CLIENT_LOGIN);    erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);    /*     * ad-hoc argument parsing     *     * We accept	-auth=[authentication type]     *			-no-exit     *			-tcp=[port]     *			-udp=[port]     * We also add a list of services that amandad can launch     */    secdrv = NULL;    in = 0; out = 1;		/* default to stdin/stdout */    have_services = 0;    for (i = 1; i < argc; i++) {	/*	 * accept -krb4 as an alias for -auth=krb4 (for compatibility)	 */	if (strcmp(argv[i], "-krb4") == 0) {	    argv[i] = "-auth=krb4";	    /* FALLTHROUGH */	    auth = "krb4";	}	/*	 * Get a driver for a security type specified after -auth=	 */	else if (strncmp(argv[i], "-auth=", strlen("-auth=")) == 0) {	    argv[i] += strlen("-auth=");	    secdrv = security_getdriver(argv[i]);	    auth = argv[i];	    if (secdrv == NULL) {		error(_("no driver for security type '%s'\n"), argv[i]);                /*NOTREACHED*/	    }	    continue;	}	/*	 * If -no-exit is specified, always run even after requests have	 * been satisfied.	 */	else if (strcmp(argv[i], "-no-exit") == 0) {	    no_exit = 1;	    continue;	}	/*	 * Allow us to directly bind to a udp port for debugging.	 * This may only apply to some security types.	 */	else if (strncmp(argv[i], "-udp=", strlen("-udp=")) == 0) {#ifdef WORKING_IPV6	    struct sockaddr_in6 sin;#else	    struct sockaddr_in sin;#endif	    argv[i] += strlen("-udp=");#ifdef WORKING_IPV6	    in = out = socket(AF_INET6, SOCK_DGRAM, 0);#else	    in = out = socket(AF_INET, SOCK_DGRAM, 0);#endif	    if (in < 0) {		error(_("can't create dgram socket: %s\n"), strerror(errno));		/*NOTREACHED*/	    }#ifdef USE_REUSEADDR	    r = setsockopt(in, SOL_SOCKET, SO_REUSEADDR,		(void *)&on, (socklen_t)sizeof(on));	    if (r < 0) {		dbprintf(_("amandad: setsockopt(SO_REUSEADDR) failed: %s\n"),			  strerror(errno));	    }#endif#ifdef WORKING_IPV6	    sin.sin6_family = (sa_family_t)AF_INET6;	    sin.sin6_addr = in6addr_any;	    sin.sin6_port = (in_port_t)htons((in_port_t)atoi(argv[i]));#else	    sin.sin_family = (sa_family_t)AF_INET;	    sin.sin_addr.s_addr = INADDR_ANY;	    sin.sin_port = (in_port_t)htons((in_port_t)atoi(argv[i]));#endif	    if (bind(in, (struct sockaddr *)&sin, (socklen_t)sizeof(sin)) < 0) {		error(_("can't bind to port %d: %s\n"), atoi(argv[i]),		    strerror(errno));		/*NOTREACHED*/	    }	}	/*	 * Ditto for tcp ports.	 */	else if (strncmp(argv[i], "-tcp=", strlen("-tcp=")) == 0) {#ifdef WORKING_IPV6	    struct sockaddr_in6 sin;#else	    struct sockaddr_in sin;#endif	    int sock;	    socklen_t n;	    argv[i] += strlen("-tcp=");#ifdef WORKING_IPV6	    sock = socket(AF_INET6, SOCK_STREAM, 0);#else	    sock = socket(AF_INET, SOCK_STREAM, 0);#endif	    if (sock < 0) {		error(_("can't create tcp socket: %s\n"), strerror(errno));		/*NOTREACHED*/	    }#ifdef USE_REUSEADDR	    r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,		(void *)&on, (socklen_t)sizeof(on));	    if (r < 0) {		dbprintf(_("amandad: setsockopt(SO_REUSEADDR) failed: %s\n"),			  strerror(errno));	    }#endif#ifdef WORKING_IPV6	    sin.sin6_family = (sa_family_t)AF_INET6;	    sin.sin6_addr = in6addr_any;	    sin.sin6_port = (in_port_t)htons((in_port_t)atoi(argv[i]));#else	    sin.sin_family = (sa_family_t)AF_INET;	    sin.sin_addr.s_addr = INADDR_ANY;	    sin.sin_port = (in_port_t)htons((in_port_t)atoi(argv[i]));#endif	    if (bind(sock, (struct sockaddr *)&sin, (socklen_t)sizeof(sin)) < 0) {		error(_("can't bind to port %d: %s\n"), atoi(argv[i]),		    strerror(errno));		/*NOTREACHED*/	    }	    listen(sock, 10);	    n = (socklen_t)sizeof(sin);	    in = out = accept(sock, (struct sockaddr *)&sin, &n);	}	/*	 * It must be a service name	 */	else {	    /* clear all services */	    if(!have_services) {		for (j = 0; j < (int)NSERVICES; j++)		    services[j].active = 0;	    }	    have_services = 1;	    if(strcmp(argv[i],"amdump") == 0) {		services[0].active = 1;		services[1].active = 1;		services[2].active = 1;		services[3].active = 1;	    }	    else {		for (j = 0; j < (int)NSERVICES; j++)		    if (strcmp(services[j].name, argv[i]) == 0)			break;		if (j == (int)NSERVICES) {		    dbprintf(_("%s: invalid service\n"), argv[i]);		    exit(1);		}		services[j].active = 1;	    }	}    }    /*     * If no security type specified, use BSD     */    if (secdrv == NULL) {	secdrv = security_getdriver("BSD");	auth = "bsd";	if (secdrv == NULL) {	    error(_("no driver for default security type 'BSD'\n"));	    /*NOTREACHED*/	}    }    if(strcasecmp(auth, "rsh") == 0 ||       strcasecmp(auth, "ssh") == 0 ||       strcasecmp(auth, "bsdtcp") == 0) {	wait_30s = 0;	exit_on_qlength = 1;    }    /* initialize */    startclock();    dbprintf(_("version %s\n"), version());    for (i = 0; version_info[i] != NULL; i++) {	dbprintf("    %s", version_info[i]);    }    if (! (argc >= 1 && argv != NULL && argv[0] != NULL)) {	dbprintf(_("WARNING: argv[0] not defined: check inetd.conf\n"));    }    /*     * Schedule to call protocol_accept() when new security handles     * are created on stdin.     */    security_accept(secdrv, amandad_get_security_conf, in, out, protocol_accept, NULL);    /*     * Schedule an event that will try to exit every 30 seconds if there     * are no requests outstanding.     */    if(wait_30s)	(void)event_register((event_id_t)30, EV_TIME, exit_check, &no_exit);    /*     * Call event_loop() with an arg of 0, telling it to block until all     * events are completed.     */    event_loop(0);    close(in);    close(out);    dbclose();    return(0);}/* * This runs periodically and checks to see if we have any active services * still running.  If we don't, then we quit. */static voidexit_check(    void *	cookie){    int no_exit;    assert(cookie != NULL);    no_exit = *(int *)cookie;    /*     * If things are still running, then don't exit.     */    if (serviceq.qlength > 0)	return;    /*     * If the caller asked us to never exit, then we're done     */    if (no_exit)	return;    dbclose();    exit(0);}/* * Handles new incoming protocol handles.  This is a callback for * security_accept(), which gets called when new handles are detected. */static voidprotocol_accept(    security_handle_t *	handle,    pkt_t *		pkt){    pkt_t pkt_out;    struct active_service *as;    char *pktbody, *tok, *service, *arguments;    char *service_path = NULL;    int i;    pkt_out.body = NULL;    /*     * If handle is NULL, then the connection is closed.     */    if(handle == NULL) {	return;    }    /*     * If pkt is NULL, then there was a problem with the new connection.     */    if (pkt == NULL) {	dbprintf(_("accept error: %s\n"), security_geterror(handle));	pkt_init(&pkt_out, P_NAK, "ERROR %s\n", security_geterror(handle));	do_sendpkt(handle, &pkt_out);	amfree(pkt_out.body);	security_close(handle);	return;    }    dbprintf(_("accept recv %s pkt:\n<<<<<\n%s>>>>>\n"),	pkt_type2str(pkt->type), pkt->body);    /*     * If this is not a REQ packet, just forget about it.     */    if (pkt->type != P_REQ) {	dbprintf(_("received unexpected %s packet:\n<<<<<\n%s>>>>>\n\n"),	    pkt_type2str(pkt->type), pkt->body);	security_close(handle);	return;    }    pktbody = service = arguments = NULL;    as = NULL;    /*     * Parse out the service and arguments     */    pktbody = stralloc(pkt->body);    tok = strtok(pktbody, " ");    if (tok == NULL)	goto badreq;    if (strcmp(tok, "SERVICE") != 0)	goto badreq;    tok = strtok(NULL, " \n");    if (tok == NULL)	goto badreq;    service = stralloc(tok);    /* we call everything else 'arguments' */    tok = strtok(NULL, "");    if (tok == NULL)	goto badreq;    arguments = stralloc(tok);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -