Exemplo n.º 1
0
NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
{
    const char *myname = "event_server_main";
    VSTREAM *stream = 0;
    char   *root_dir = 0;
    char   *user_name = 0;
    int     debug_me = 0;
    int     daemon_mode = 1;
    char   *service_name = basename(argv[0]);
    int     delay;
    int     c;
    int     fd;
    va_list ap;
    MAIL_SERVER_INIT_FN pre_init = 0;
    MAIL_SERVER_INIT_FN post_init = 0;
    MAIL_SERVER_LOOP_FN loop = 0;
    int     key;
    char   *transport = 0;

#if 0
    char   *lock_path;
    VSTRING *why;

#endif
    int     alone = 0;
    int     zerolimit = 0;
    WATCHDOG *watchdog;
    char   *oname_val;
    char   *oname;
    char   *oval;
    const char *err;
    char   *generation;
    int     msg_vstream_needed = 0;
    int     redo_syslog_init = 0;

    /*
     * Process environment options as early as we can.
     */
    if (getenv(CONF_ENV_VERB))
	msg_verbose = 1;
    if (getenv(CONF_ENV_DEBUG))
	debug_me = 1;

    /*
     * Don't die when a process goes away unexpectedly.
     */
    signal(SIGPIPE, SIG_IGN);

    /*
     * Don't die for frivolous reasons.
     */
#ifdef SIGXFSZ
    signal(SIGXFSZ, SIG_IGN);
#endif

    /*
     * May need this every now and then.
     */
    var_procname = mystrdup(basename(argv[0]));
    set_mail_conf_str(VAR_PROCNAME, var_procname);

    /*
     * Initialize logging and exit handler. Do the syslog first, so that its
     * initialization completes before we enter the optional chroot jail.
     */
    msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
    if (msg_verbose)
	msg_info("daemon started");

    /*
     * Check the Postfix library version as soon as we enable logging.
     */
    MAIL_VERSION_CHECK;

    /*
     * Initialize from the configuration file. Allow command-line options to
     * override compiled-in defaults or configured parameter values.
     */
    mail_conf_suck();

    /*
     * Register dictionaries that use higher-level interfaces and protocols.
     */
    mail_dict_init();

    /*
     * After database open error, continue execution with reduced
     * functionality.
     */
    dict_allow_surrogate = 1;

    /*
     * Pick up policy settings from master process. Shut up error messages to
     * stderr, because no-one is going to see them.
     */
    opterr = 0;
    while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) {
	switch (c) {
	case 'c':
	    root_dir = "setme";
	    break;
	case 'd':
	    daemon_mode = 0;
	    break;
	case 'D':
	    debug_me = 1;
	    break;
	case 'i':
	    mail_conf_update(VAR_MAX_IDLE, optarg);
	    break;
	case 'l':
	    alone = 1;
	    break;
	case 'm':
	    mail_conf_update(VAR_MAX_USE, optarg);
	    break;
	case 'n':
	    service_name = optarg;
	    break;
	case 'o':
	    oname_val = mystrdup(optarg);
	    if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
		msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
	    mail_conf_update(oname, oval);
	    if (strcmp(oname, VAR_SYSLOG_NAME) == 0)
		redo_syslog_init = 1;
	    myfree(oname_val);
	    break;
	case 's':
	    if ((socket_count = atoi(optarg)) <= 0)
		msg_fatal("invalid socket_count: %s", optarg);
	    break;
	case 'S':
	    stream = VSTREAM_IN;
	    break;
	case 'u':
	    user_name = "setme";
	    break;
	case 't':
	    transport = optarg;
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	case 'V':
	    if (++msg_vstream_needed == 1)
		msg_vstream_init(mail_task(var_procname), VSTREAM_ERR);
	    break;
	case 'z':
	    zerolimit = 1;
	    break;
	default:
	    msg_fatal("invalid option: %c", c);
	    break;
	}
    }

    /*
     * Initialize generic parameters.
     */
    mail_params_init();
    if (redo_syslog_init)
	msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);

    /*
     * If not connected to stdin, stdin must not be a terminal.
     */
    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
	msg_vstream_init(var_procname, VSTREAM_ERR);
	msg_fatal("do not run this command by hand");
    }

    /*
     * Application-specific initialization.
     */
    va_start(ap, service);
    while ((key = va_arg(ap, int)) != 0) {
	switch (key) {
	case MAIL_SERVER_INT_TABLE:
	    get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
	    break;
	case MAIL_SERVER_LONG_TABLE:
	    get_mail_conf_long_table(va_arg(ap, CONFIG_LONG_TABLE *));
	    break;
	case MAIL_SERVER_STR_TABLE:
	    get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
	    break;
	case MAIL_SERVER_BOOL_TABLE:
	    get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
	    break;
	case MAIL_SERVER_TIME_TABLE:
	    get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
	    break;
	case MAIL_SERVER_RAW_TABLE:
	    get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
	    break;
	case MAIL_SERVER_NINT_TABLE:
	    get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *));
	    break;
	case MAIL_SERVER_NBOOL_TABLE:
	    get_mail_conf_nbool_table(va_arg(ap, CONFIG_NBOOL_TABLE *));
	    break;
	case MAIL_SERVER_PRE_INIT:
	    pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
	    break;
	case MAIL_SERVER_POST_INIT:
	    post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
	    break;
	case MAIL_SERVER_LOOP:
	    loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
	    break;
	case MAIL_SERVER_EXIT:
	    event_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
	    break;
	case MAIL_SERVER_PRE_ACCEPT:
	    event_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
	    break;
	case MAIL_SERVER_PRE_DISCONN:
	    event_server_pre_disconn = va_arg(ap, MAIL_SERVER_DISCONN_FN);
	    break;
	case MAIL_SERVER_IN_FLOW_DELAY:
	    event_server_in_flow_delay = 1;
	    break;
	case MAIL_SERVER_SOLITARY:
	    if (stream == 0 && !alone)
		msg_fatal("service %s requires a process limit of 1",
			  service_name);
	    break;
	case MAIL_SERVER_UNLIMITED:
	    if (stream == 0 && !zerolimit)
		msg_fatal("service %s requires a process limit of 0",
			  service_name);
	    break;
	case MAIL_SERVER_PRIVILEGED:
	    if (user_name)
		msg_fatal("service %s requires privileged operation",
			  service_name);
	    break;
	case MAIL_SERVER_WATCHDOG:
	    event_server_watchdog = *va_arg(ap, int *);
	    break;
	case MAIL_SERVER_SLOW_EXIT:
	    event_server_slow_exit = va_arg(ap, MAIL_SERVER_SLOW_EXIT_FN);
	    break;
	default:
	    msg_panic("%s: unknown argument type: %d", myname, key);
	}
    }
    va_end(ap);

    if (root_dir)
	root_dir = var_queue_dir;
    if (user_name)
	user_name = var_mail_owner;

    /*
     * Can options be required?
     */
    if (stream == 0) {
	if (transport == 0)
	    msg_fatal("no transport type specified");
	if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
	    event_server_accept = event_server_accept_inet;
	else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
	    event_server_accept = event_server_accept_local;
#ifdef MASTER_XPORT_NAME_PASS
	else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
	    event_server_accept = event_server_accept_pass;
#endif
	else
	    msg_fatal("unsupported transport type: %s", transport);
    }

    /*
     * Retrieve process generation from environment.
     */
    if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
	if (!alldig(generation))
	    msg_fatal("bad generation: %s", generation);
	OCTAL_TO_UNSIGNED(event_server_generation, generation);
	if (msg_verbose)
	    msg_info("process generation: %s (%o)",
		     generation, event_server_generation);
    }

    /*
     * Optionally start the debugger on ourself.
     */
    if (debug_me)
	debug_process();

    /*
     * Traditionally, BSD select() can't handle multiple processes selecting
     * on the same socket, and wakes up every process in select(). See TCP/IP
     * Illustrated volume 2 page 532. We avoid select() collisions with an
     * external lock file.
     */

    /*
     * XXX Can't compete for exclusive access to the listen socket because we
     * also have to monitor existing client connections for service requests.
     */
#if 0
    if (stream == 0 && !alone) {
	lock_path = concatenate(DEF_PID_DIR, "/", transport,
				".", service_name, (char *) 0);
	why = vstring_alloc(1);
	if ((event_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
				      (struct stat *) 0, -1, -1, why)) == 0)
	    msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
	close_on_exec(vstream_fileno(event_server_lock), CLOSE_ON_EXEC);
	myfree(lock_path);
	vstring_free(why);
    }
#endif

    /*
     * Set up call-back info.
     */
    event_server_service = service;
    event_server_name = service_name;
    event_server_argv = argv + optind;

    /*
     * Run pre-jail initialization.
     */
    if (chdir(var_queue_dir) < 0)
	msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
    if (pre_init)
	pre_init(event_server_name, event_server_argv);

    /*
     * Optionally, restrict the damage that this process can do.
     */
    resolve_local_init();
    tzset();
    chroot_uid(root_dir, user_name);

    /*
     * Run post-jail initialization.
     */
    if (post_init)
	post_init(event_server_name, event_server_argv);

    /*
     * Are we running as a one-shot server with the client connection on
     * standard input? If so, make sure the output is written to stdout so as
     * to satisfy common expectation.
     */
    if (stream != 0) {
	vstream_control(stream,
			VSTREAM_CTL_DOUBLE,
			VSTREAM_CTL_WRITE_FD, STDOUT_FILENO,
			VSTREAM_CTL_END);
	service(stream, event_server_name, event_server_argv);
	vstream_fflush(stream);
	event_server_exit();
    }

    /*
     * Running as a semi-resident server. Service connection requests.
     * Terminate when we have serviced a sufficient number of clients, when
     * no-one has been talking to us for a configurable amount of time, or
     * when the master process terminated abnormally.
     */
    if (var_idle_limit > 0)
	event_request_timer(event_server_timeout, (char *) 0, var_idle_limit);
    for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
	event_enable_read(fd, event_server_accept, CAST_INT_TO_CHAR_PTR(fd));
	close_on_exec(fd, CLOSE_ON_EXEC);
    }
    event_enable_read(MASTER_STATUS_FD, event_server_abort, (char *) 0);
    close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
    watchdog = watchdog_create(event_server_watchdog,
			       (WATCHDOG_FN) 0, (char *) 0);

    /*
     * The event loop, at last.
     */
    while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
	if (event_server_lock != 0) {
	    watchdog_stop(watchdog);
	    if (myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
			MYFLOCK_OP_EXCLUSIVE) < 0)
		msg_fatal("select lock: %m");
	}
	watchdog_start(watchdog);
	delay = loop ? loop(event_server_name, event_server_argv) : -1;
	event_loop(delay);
    }
    event_server_exit();
}
Exemplo n.º 2
0
Arquivo: lpr.c Projeto: OPSF/uClinux
int
main(int argc, char **argv)
{
	struct passwd *pw;
	struct group *gptr;
	char *arg, *cp;
	char buf[MAXPATHLEN];
	int i, f, ch;
	struct stat stb;

	/*
	 * Simulate setuid daemon w/ PRIV_END called.
	 * We don't want lpr to actually be setuid daemon since that
	 * requires that the lpr binary be owned by user daemon, which
	 * is potentially unsafe.
	 */
	if ((pw = getpwnam(DEFUID)) == NULL)
		errx(1, "'lp' uid not in password file");
	effective_uid = pw->pw_uid;
	real_uid = getuid();
	effective_gid = pw->pw_gid;
	real_gid = getgid();
	setresgid(real_gid, real_gid, effective_gid);
	setresuid(real_uid, real_uid, effective_uid);

	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
		signal(SIGHUP, cleanup);
	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, cleanup);
	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
		signal(SIGQUIT, cleanup);
	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
		signal(SIGTERM, cleanup);

	gethostname(host, sizeof (host));
	openlog("lpr", 0, LOG_LPR);

	while ((ch = getopt(argc, argv,
	    ":#:1:2:3:4:C:J:P:T:U:cdfghi::klmnpqrstvw:")) != -1) {
		switch (ch) {

		case '#':		/* n copies */
			if (isdigit(*optarg)) {
				i = atoi(optarg);
				if (i > 0)
					ncopies = i;
			}

		case '4':		/* troff fonts */
		case '3':
		case '2':
		case '1':
			fonts[ch - '1'] = optarg;
			break;

		case 'C':		/* classification spec */
			hdr++;
			class = optarg;
			break;

		case 'J':		/* job name */
			hdr++;
			jobname = optarg;
			break;

		case 'P':		/* specifiy printer name */
			printer = optarg;
			break;

		case 'T':		/* pr's title line */
			title = optarg;
			break;

		case 'U':		/* user name */
			hdr++;
			person = optarg;
			break;

		case 'c':		/* print cifplot output */
		case 'd':		/* print tex output (dvi files) */
		case 'g':		/* print graph(1G) output */
		case 'l':		/* literal output */
		case 'n':		/* print ditroff output */
		case 'p':		/* print using ``pr'' */
		case 't':		/* print troff output (cat files) */
		case 'v':		/* print vplot output */
			format = ch;
			break;

		case 'f':		/* print fortran output */
			format = 'r';
			break;

		case 'h':		/* toggle want of header page */
			hdr = !hdr;
			break;

		case 'i':		/* indent output */
			iflag++;
			if ( optarg == 0 || (indent = atoi(optarg)) < 0)
				indent = 8;
			break;

		case 'm':		/* send mail when done */
			mailflg++;
			break;

		case 'q':		/* just q job */
			qflag++;
			break;

		case 'r':		/* remove file when done */
			rflag++;
			break;

		case 's':		/* try to link files */
			sflag++;
			break;

		case 'k':		/* try to relink files */
			kflag++;
			rflag++;
			break;

		case 'w':		/* versatec page width */
			width = optarg;
			break;

		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;
	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
		printer = DEFLP;
	chkprinter(printer);
	if (SC && ncopies > 1)
		errx(1, "multiple copies are not allowed");
	if (MC > 0 && ncopies > MC)
		errx(1, "only %ld copies are allowed", MC);
	/*
	 * Get the identity of the person doing the lpr using the same
	 * algorithm as lprm. 
	 */
	if (real_uid != DU || person == NULL) {
		if ((pw = getpwuid(real_uid)) == NULL)
			errx(1, "Who are you?");
		if ((person = strdup(pw->pw_name)) == NULL)
			err(1, NULL);
	}
	/*
	 * Check for restricted group access.
	 */
	if (RG != NULL && real_uid != DU) {
		if ((gptr = getgrnam(RG)) == NULL)
			errx(1, "Restricted group specified incorrectly");
		if (gptr->gr_gid != getgid()) {
			while (*gptr->gr_mem != NULL) {
				if ((strcmp(person, *gptr->gr_mem)) == 0)
					break;
				gptr->gr_mem++;
			}
			if (*gptr->gr_mem == NULL)
				errx(1, "Not a member of the restricted group");
		}
	}
	/*
	 * Check to make sure queuing is enabled if real_uid is not root.
	 */
	(void)snprintf(buf, sizeof(buf), "%s/%s", SD, LO);
	if (real_uid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
		errx(1, "Printer queue is disabled");
	/*
	 * Initialize the control file.
	 */
	mktemps();
	tfd = nfile(tfname);
	card('H', host);
	card('P', person);
	if (hdr && !SH) {
		if (jobname == NULL) {
			if (argc == 0)
				jobname = "stdin";
			else
				jobname = (arg = strrchr(argv[0], '/')) ?
				    arg + 1 : argv[0];
		}
		card('J', jobname);
		card('C', class);
		card('L', person);
	}
	if (iflag)
		card('I', itoa(indent));
	if (mailflg)
		card('M', person);
	if (format == 't' || format == 'n' || format == 'd')
		for (i = 0; i < 4; i++)
			if (fonts[i] != NULL)
				card('1'+i, fonts[i]);
	if (width != NULL)
		card('W', width);

	/*
	 * Read the files and spool them.
	 */
	if (argc == 0)
		copy(0, " ");
	else while (argc--) {
		if (argv[0][0] == '-' && argv[0][1] == '\0') {
			/* use stdin */
			copy(0, " ");
			argv++;
			continue;
		}
		if ((f = test(arg = *argv++)) < 0)
			continue;	/* file unreasonable */

		if (sflag && (cp = linked(arg)) != NULL) {
			(void)snprintf(buf, sizeof(buf), "%d %d",
			    makedev( major(statb.st_dev), minor(statb.st_dev)), (int)statb.st_ino);
			card('S', buf);
			if (format == 'p')
				card('T', title ? title : arg);
			for (i = 0; i < ncopies; i++)
				card(format, &dfname[inchar-2]);
			card('U', &dfname[inchar-2]);
			if (f)
				card('U', cp);
			card('N', arg);
			dfname[inchar]++;
			nact++;
			continue;
		}
		if (kflag && rename(arg, dfname) == 0) {
			if (format == 'p')
				card('T', title ? title : arg);
			for (i = 0; i < ncopies; i++)
				card(format, &dfname[inchar-2]);
			card('U', &dfname[inchar-2]);
			card('N', arg);
			nact++;
			continue;
		}
		if (kflag || sflag)
			syslog(LOG_WARNING, "%s: not %slinked, copying instead", arg, kflag ? "re" : "");
		if ((i = safe_open(arg, O_RDONLY, 0)) < 0)
			warn("%s", arg);
		else {
			copy(i, arg);
			(void)close(i);
			if (f && unlink(arg) < 0)
				warnx("%s: not removed", arg);
		}
	}

	if (nact) {
		(void)close(tfd);
		tfname[inchar]--;
		/*
		 * Touch the control file to fix position in the queue.
		 */
		PRIV_START;
		if ((tfd = safe_open(tfname, O_RDWR|O_NOFOLLOW, 0)) >= 0) {
			char c;

			if (read(tfd, &c, 1) == 1 &&
			    lseek(tfd, (off_t)0, 0) == 0 &&
			    write(tfd, &c, 1) != 1) {
				warn("%s", tfname);
				tfname[inchar]++;
				cleanup(0);
			}
			(void)close(tfd);
		}
#ifdef EMBED
		if (rename(tfname, cfname) < 0) {
#else
		if (link(tfname, cfname) < 0) {
#endif
			warn("cannot rename %s", cfname);
			tfname[inchar]++;
			cleanup(0);
		}
#ifndef EMBED
		unlink(tfname);
#endif
		PRIV_END;
		if (qflag)		/* just q things up */
			exit(0);
		if (!startdaemon(printer))
			printf("jobs queued, but cannot start daemon.\n");
		exit(0);
	}
	cleanup(0);
	return (1);
	/* NOTREACHED */
}

/*
 * Create the file n and copy from file descriptor f.
 */
static void
copy(int f, char *n)
{
	int fd, i, nr, nc;
	char buf[BUFSIZ];

	if (format == 'p')
		card('T', title ? title : n);
	for (i = 0; i < ncopies; i++)
		card(format, &dfname[inchar-2]);
	card('U', &dfname[inchar-2]);
	card('N', n);
	fd = nfile(dfname);
	nr = nc = 0;
	while ((i = read(f, buf, sizeof(buf))) > 0) {
		if (write(fd, buf, i) != i) {
			warn("%s", n);
			break;
		}
		nc += i;
		if (nc >= sizeof(buf)) {
			nc -= sizeof(buf);
			nr++;
			if (MX > 0 && nr > MX) {
				warnx("%s: copy file is too large", n);
				break;
			}
		}
	}
	(void)close(fd);
	if (nc==0 && nr==0) 
		warnx("%s: empty input file", f ? n : "stdin");
	else
		nact++;
}
Exemplo n.º 3
0
static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, unsigned int options)
{
	int ret = 0, fd, included;
	unsigned i;
	const struct optstruct *opt;
	const char *virname;
	STATBUF sb;
	struct metachain chain;

    if((opt = optget(opts, "exclude"))->enabled) {
	while(opt) {
	    if(match_regex(filename, opt->strarg) == 1) {
		if(!printinfected)
		    logg("~%s: Excluded\n", filename);
		return;
	    }
	    opt = opt->nextarg;
	}
    }

    if((opt = optget(opts, "include"))->enabled) {
	included = 0;
	while(opt) {
	    if(match_regex(filename, opt->strarg) == 1) {
		included = 1;
		break;
	    }
	    opt = opt->nextarg;
	}
	if(!included) {
	    if(!printinfected)
		logg("~%s: Excluded\n", filename);
	    return;
	}
    }

    /* argh, don't scan /proc files */
    if(STAT(filename, &sb) != -1) {
#ifdef C_LINUX
	if(procdev && sb.st_dev == procdev) {
	    if(!printinfected)
		logg("~%s: Excluded (/proc)\n", filename);
		return;
	}
#endif    
	if(!sb.st_size) {
	    if(!printinfected)
		logg("~%s: Empty file\n", filename);
	    return;
	}
	info.rblocks += sb.st_size / CL_COUNT_PRECISION;
    }

#ifndef _WIN32
    if(geteuid())
	if(checkaccess(filename, NULL, R_OK) != 1) {
	    if(!printinfected)
		logg("~%s: Access denied\n", filename);
	    info.errors++;
	    return;
	}
#endif

    memset(&chain, 0, sizeof(chain));
    if(optget(opts, "archive-verbose")->enabled) {
	chain.chains = malloc(sizeof(*chain.chains));
	if (chain.chains) {
	    chain.chains[0] = strdup(filename);
	    chain.n = 1;
	}
    }
    logg("*Scanning %s\n", filename);

    if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1) {
	logg("^Can't open file %s: %s\n", filename, strerror(errno));
	info.errors++;
	return;
    }


    if((ret = cl_scandesc_callback(fd, &virname, &info.blocks, engine, options, &chain)) == CL_VIRUS) {
	if(optget(opts, "archive-verbose")->enabled) {
	    if (chain.n > 1) {
		char str[128];
		int toolong = print_chain(&chain, str, sizeof(str));
		logg("~%s%s!(%d)%s: %s FOUND\n", str, toolong ? "..." : "", chain.lastvir-1, chain.chains[chain.n-1], virname);
	    } else if (chain.lastvir)
		logg("~%s!(%d): %s FOUND\n", filename, chain.lastvir-1, virname);
	}
	logg("~%s: %s FOUND\n", filename, virname);
	info.files++;
	info.ifiles++;

	if(bell)
	    fprintf(stderr, "\007");

    } else if(ret == CL_CLEAN) {
	if(!printinfected && printclean)
	    mprintf("~%s: OK\n", filename);
	info.files++;
    } else {
	if(!printinfected)
	    logg("~%s: %s ERROR\n", filename, cl_strerror(ret));
	info.errors++;
    }

    for (i=0;i<chain.n;i++)
	free(chain.chains[i]);
    free(chain.chains);
    close(fd);

    if(ret == CL_VIRUS && action)
	action(filename);
}
Exemplo n.º 4
0
FILE *
ns_os_openfile(const char *filename, mode_t mode, isc_boolean_t switch_user) {
	char strbuf[ISC_STRERRORSIZE], *f;
	FILE *fp;
	int fd;

	/*
	 * Make the containing directory if it doesn't exist.
	 */
	f = strdup(filename);
	if (f == NULL) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		ns_main_earlywarning("couldn't strdup() '%s': %s",
				     filename, strbuf);
		return (NULL);
	}
	if (mkdirpath(f, ns_main_earlywarning) == -1) {
		free(f);
		return (NULL);
	}
	free(f);

	if (switch_user && runas_pw != NULL) {
#ifndef HAVE_LINUXTHREADS
		gid_t oldgid = getgid();
#endif
		/* Set UID/GID to the one we'll be running with eventually */
		setperms(runas_pw->pw_uid, runas_pw->pw_gid);

		fd = safe_open(filename, mode, ISC_FALSE);

#ifndef HAVE_LINUXTHREADS
		/* Restore UID/GID to root */
		setperms(0, oldgid);
#endif /* HAVE_LINUXTHREADS */

		if (fd == -1) {
#ifndef HAVE_LINUXTHREADS
			fd = safe_open(filename, mode, ISC_FALSE);
			if (fd != -1) {
				ns_main_earlywarning("Required root "
						     "permissions to open "
						     "'%s'.", filename);
			} else {
				ns_main_earlywarning("Could not open "
						     "'%s'.", filename);
			}
			ns_main_earlywarning("Please check file and "
					     "directory permissions "
					     "or reconfigure the filename.");
#else /* HAVE_LINUXTHREADS */
			ns_main_earlywarning("Could not open "
					     "'%s'.", filename);
			ns_main_earlywarning("Please check file and "
					     "directory permissions "
					     "or reconfigure the filename.");
#endif /* HAVE_LINUXTHREADS */
		}
	} else {
		fd = safe_open(filename, mode, ISC_FALSE);
	}

	if (fd < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		ns_main_earlywarning("could not open file '%s': %s",
				     filename, strbuf);
		return (NULL);
	}

	fp = fdopen(fd, "w");
	if (fp == NULL) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		ns_main_earlywarning("could not fdopen() file '%s': %s",
				     filename, strbuf);
	}

	return (fp);
}
Exemplo n.º 5
0
void
ns_os_writepidfile(const char *filename, isc_boolean_t first_time) {
	int fd;
	FILE *lockfile;
	size_t len;
	pid_t pid;
	char strbuf[ISC_STRERRORSIZE];
	void (*report)(const char *, ...);

	/*
	 * The caller must ensure any required synchronization.
	 */

	report = first_time ? ns_main_earlyfatal : ns_main_earlywarning;

	cleanup_pidfile();

	if (strcmp(filename, "none") == 0)
		return;
	len = strlen(filename);
	pidfile = malloc(len + 1);
	if (pidfile == NULL) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		(*report)("couldn't malloc '%s': %s", filename, strbuf);
		return;
	}
	/* This is safe. */
	strcpy(pidfile, filename);

	fd = safe_open(filename, ISC_FALSE);
	if (fd < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		(*report)("couldn't open pid file '%s': %s", filename, strbuf);
		free(pidfile);
		pidfile = NULL;
		return;
	}
	lockfile = fdopen(fd, "w");
	if (lockfile == NULL) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		(*report)("could not fdopen() pid file '%s': %s",
			  filename, strbuf);
		(void)close(fd);
		cleanup_pidfile();
		return;
	}

	pid = getpid();

	if (fprintf(lockfile, "%ld\n", (long)pid) < 0) {
		(*report)("fprintf() to pid file '%s' failed", filename);
		(void)fclose(lockfile);
		cleanup_pidfile();
		return;
	}
	if (fflush(lockfile) == EOF) {
		(*report)("fflush() to pid file '%s' failed", filename);
		(void)fclose(lockfile);
		cleanup_pidfile();
		return;
	}
	(void)fclose(lockfile);
}
Exemplo n.º 6
0
Arquivo: flush.c Projeto: ii0/postfix
static int flush_one_file(const char *queue_id, VSTRING *queue_file,
			          struct utimbuf * tbuf, int how)
{
    const char *myname = "flush_one_file";
    const char *queue_name;
    const char *path;

    /*
     * Some other instance of this program may flush some logfile and may
     * just have moved this queue file to the incoming queue.
     */
    for (queue_name = MAIL_QUEUE_DEFERRED; /* see below */ ;
	 queue_name = MAIL_QUEUE_INCOMING) {
	path = mail_queue_path(queue_file, queue_name, queue_id);
	if (utime(path, tbuf) == 0)
	    break;
	if (errno != ENOENT)
	    msg_warn("%s: update %s time stamps: %m", myname, path);
	if (STREQ(queue_name, MAIL_QUEUE_INCOMING))
	    return (0);
    }

    /*
     * With the UNTHROTTLE_AFTER strategy, we leave it up to the queue
     * manager to unthrottle transports and queues as it reads recipients
     * from a queue file. We request this unthrottle operation by setting the
     * group read permission bit.
     * 
     * Note: we must avoid using chmod(). It is not only slower than fchmod()
     * but it is also less secure. With chmod(), an attacker could repeatedly
     * send requests to the flush server and trick it into changing
     * permissions of non-queue files, by exploiting a race condition.
     * 
     * We use safe_open() because we don't validate the file content before
     * modifying the file status.
     */
    if (how & UNTHROTTLE_AFTER) {
	VSTRING *why;
	struct stat st;
	VSTREAM *fp;

	for (why = vstring_alloc(1); /* see below */ ;
	     queue_name = MAIL_QUEUE_INCOMING,
	     path = mail_queue_path(queue_file, queue_name, queue_id)) {
	    if ((fp = safe_open(path, O_RDWR, 0, &st, -1, -1, why)) != 0)
		break;
	    if (errno != ENOENT)
		msg_warn("%s: open %s: %s", myname, path, STR(why));
	    if (errno != ENOENT || STREQ(queue_name, MAIL_QUEUE_INCOMING)) {
		vstring_free(why);
		return (0);
	    }
	}
	vstring_free(why);
	if ((st.st_mode & MAIL_QUEUE_STAT_READY) != MAIL_QUEUE_STAT_READY) {
	    (void) vstream_fclose(fp);
	    return (0);
	}
	if (fchmod(vstream_fileno(fp), st.st_mode | MAIL_QUEUE_STAT_UNTHROTTLE) < 0)
	    msg_warn("%s: fchmod %s: %m", myname, path);
	(void) vstream_fclose(fp);
    }

    /*
     * Move the file to the incoming queue, if it isn't already there.
     */
    if (STREQ(queue_name, MAIL_QUEUE_INCOMING) == 0
	&& mail_queue_rename(queue_id, queue_name, MAIL_QUEUE_INCOMING) < 0
	&& errno != ENOENT)
	msg_warn("%s: rename from %s to %s: %m",
		 path, queue_name, MAIL_QUEUE_INCOMING);

    /*
     * If we got here, we achieved something, so let's claim succes.
     */
    return (1);
}
Exemplo n.º 7
0
SHMem *
SHMem::initSegment(const char *name, int size, bool &init)
{
    bool needInit = true;
    /* big enough to hold a uid_t value in decimal */
    /* decimal digits = ceiling(log10(uid_t_max)); */
    /* log10(uid_t_max) = log256(uid_t_max)/log256(10); */
    /* log256(uid_t_max) = sizeof(uid_t); */
    /* log10(256) just greater than .41 */
    /* so decimal_digits = (sizeof(uid_t)*100 +40)/41 */
#define UID_DIGITS (((sizeof(uid_t)*100)+40)/41)
    char uid_str[UID_DIGITS+2]; /* 1 for '-', 1 for null */
   
    init = 0;
    SHMemData *shmemData = new SHMemData;
    if (!shmemData ) {
	// applications know we failed because they will get a NULL address
	// from getSHMemAddr.
	return NULL;
    }
    int mask = umask(0);
    int ret = mkdir (MEMSEGPATH, 01777);
    umask(mask);
    if ((ret == -1) && (errno != EEXIST)) {
	delete shmemData;
	return NULL;
    }
    /* 1 for the '/', one for the '-' and one for the null */
    shmemData->path = new char [sizeof(MEMSEGPATH)+strlen(name)+UID_DIGITS+3];
    if (shmemData->path == NULL) {
	delete shmemData;
	return NULL;
    }
    memcpy(shmemData->path,MEMSEGPATH, sizeof(MEMSEGPATH));
    shmemData->path[sizeof(MEMSEGPATH)-1] = '/';
    strcpy(&shmemData->path[sizeof(MEMSEGPATH)],name);

    sprintf(uid_str, "-%u",getuid());
    strcat(shmemData->path,uid_str);
    int mode = 0600;

    shmemData->fd = open(shmemData->path, 
		O_CREAT|O_RDWR|O_EXCL|O_APPEND|O_EXLOCK, mode);
    if (shmemData->fd >= 0) {
	char *buf;
	int len = size+RESERVED_OFFSET;
        int ret;

	buf = (char *)calloc(1,len);
	if (!buf) {
	    unlink(shmemData->path);
#ifdef FULL_CLEANUP
	    flock(shmemData->fd, LOCK_UN);
#endif
	    delete shmemData;
	    return NULL;
	}
	ret = write(shmemData->fd,buf,len);
        if (ret != len) {
	    unlink(shmemData->path);
#ifdef FULL_CLEANUP
	    flock(shmemData->fd, LOCK_UN);
#endif
	    delete shmemData;
	    return NULL;
	}
	free(buf);
    } else if (errno == EEXIST) {
	needInit = false;
	shmemData->fd = safe_open(shmemData->path,O_RDWR|O_EXLOCK, mode,
				  size+RESERVED_OFFSET);
    }
    if (shmemData->fd < 0) {
	delete shmemData;
	return NULL;
    }
    shmemData->addr = (char *) mmap(0, size+RESERVED_OFFSET, 
			PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED|MAP_INHERIT, 
							shmemData->fd, 0);
    if (shmemData->addr == NULL) {
	if (needInit) {
	    unlink(shmemData->path);
	}
#ifdef FULL_CLEANUP
	flock(shmemData->fd, LOCK_UN);
#endif
	delete shmemData;
	return NULL;
    }
    shmemData->size = size;
#ifdef FULL_CLEANUP
    (*(unsigned long *)shmemData->addr)++; 
    flock(shmemData->fd, LOCK_UN);
#endif
    init = needInit;
    SHMem *memseg;

    memseg = new SHMem();
    if (!memseg) {
	delete shmemData;
	return NULL;
    }
    memseg->shmemData = shmemData;
    return memseg;
}
Exemplo n.º 8
0
NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,...)
{
    char   *myname = "trigger_server_main";
    char   *root_dir = 0;
    char   *user_name = 0;
    int     debug_me = 0;
    char   *service_name = basename(argv[0]);
    VSTREAM *stream = 0;
    int     delay;
    int     c;
    int     socket_count = 1;
    int     fd;
    va_list ap;
    MAIL_SERVER_INIT_FN pre_init = 0;
    MAIL_SERVER_INIT_FN post_init = 0;
    MAIL_SERVER_LOOP_FN loop = 0;
    int     key;
    char    buf[TRIGGER_BUF_SIZE];
    int     len;
    char   *transport = 0;
    char   *lock_path;
    VSTRING *why;
    int     alone = 0;
    int     zerolimit = 0;
    WATCHDOG *watchdog;
    char   *oval;

    /*
     * Process environment options as early as we can.
     */
    if (getenv(CONF_ENV_VERB))
	msg_verbose = 1;
    if (getenv(CONF_ENV_DEBUG))
	debug_me = 1;

    /*
     * Don't die when a process goes away unexpectedly.
     */
    signal(SIGPIPE, SIG_IGN);

    /*
     * Don't die for frivolous reasons.
     */
#ifdef SIGXFSZ
    signal(SIGXFSZ, SIG_IGN);
#endif

    /*
     * May need this every now and then.
     */
    var_procname = mystrdup(basename(argv[0]));
    set_mail_conf_str(VAR_PROCNAME, var_procname);

    /*
     * Initialize logging and exit handler. Do the syslog first, so that its
     * initialization completes before we enter the optional chroot jail.
     */
    msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
    if (msg_verbose)
	msg_info("daemon started");

    /*
     * Initialize from the configuration file. Allow command-line options to
     * override compiled-in defaults or configured parameter values.
     */
    mail_conf_suck();

    /*
     * Register dictionaries that use higher-level interfaces and protocols.
     */
    mail_dict_init();

    /*
     * Pick up policy settings from master process. Shut up error messages to
     * stderr, because no-one is going to see them.
     */
    opterr = 0;
    while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uvzZ")) > 0) {
	switch (c) {
	case 'c':
	    root_dir = "setme";
	    break;
	case 'D':
	    debug_me = 1;
	    break;
	case 'i':
	    mail_conf_update(VAR_MAX_IDLE, optarg);
	    break;
	case 'l':
	    alone = 1;
	    break;
	case 'm':
	    mail_conf_update(VAR_MAX_USE, optarg);
	    break;
	case 'n':
	    service_name = optarg;
	    break;
	case 'o':
	    if ((oval = split_at(optarg, '=')) == 0)
		oval = "";
	    mail_conf_update(optarg, oval);
	    break;
	case 's':
	    if ((socket_count = atoi(optarg)) <= 0)
		msg_fatal("invalid socket_count: %s", optarg);
	    break;
	case 'S':
	    stream = VSTREAM_IN;
	    break;
	case 't':
	    transport = optarg;
	    break;
	case 'u':
	    user_name = "setme";
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	case 'z':
	    zerolimit = 1;
	    break;
	case 'Z':
	    msg_debug++;
	    break;
	default:
	    msg_fatal("invalid option: %c", c);
	    break;
	}
    }

    /*
     * Initialize generic parameters.
     */
    mail_params_init();

    /*
     * Application-specific initialization.
     */
    va_start(ap, service);
    while ((key = va_arg(ap, int)) != 0) {
	switch (key) {
	case MAIL_SERVER_INT_TABLE:
	    get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
	    break;
	case MAIL_SERVER_STR_TABLE:
	    get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
	    break;
	case MAIL_SERVER_BOOL_TABLE:
	    get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
	    break;
	case MAIL_SERVER_TIME_TABLE:
	    get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
	    break;
	case MAIL_SERVER_RAW_TABLE:
	    get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
	    break;
	case MAIL_SERVER_PRE_INIT:
	    pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
	    break;
	case MAIL_SERVER_POST_INIT:
	    post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
	    break;
	case MAIL_SERVER_LOOP:
	    loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
	    break;
	case MAIL_SERVER_EXIT:
	    trigger_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
	    break;
	case MAIL_SERVER_PRE_ACCEPT:
	    trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
	    break;
	case MAIL_SERVER_IN_FLOW_DELAY:
	    trigger_server_in_flow_delay = 1;
	    break;
	case MAIL_SERVER_SOLITARY:
	    if (!alone)
		msg_fatal("service %s requires a process limit of 1",
			  service_name);
	    break;
	case MAIL_SERVER_UNLIMITED:
	    if (!zerolimit)
		msg_fatal("service %s requires a process limit of 0",
			  service_name);
	    break;
	default:
	    msg_panic("%s: unknown argument type: %d", myname, key);
	}
    }
    va_end(ap);

    if (root_dir)
	root_dir = var_queue_dir;
    if (user_name)
	user_name = var_mail_owner;

    /*
     * If not connected to stdin, stdin must not be a terminal.
     */
    if (stream == 0 && isatty(STDIN_FILENO)) {
	msg_vstream_init(var_procname, VSTREAM_ERR);
	msg_fatal("do not run this command by hand");
    }

    /*
     * Can options be required?
     * 
     * XXX Initially this code was implemented with UNIX-domain sockets, but
     * Solaris <= 2.5 UNIX-domain sockets misbehave hopelessly when the
     * client disconnects before the server has accepted the connection.
     * Symptom: the server accept() fails with EPIPE or EPROTO, but the
     * socket stays readable, so that the program goes into a wasteful loop.
     * 
     * The initial fix was to use FIFOs, but those turn out to have their own
     * problems, witness the workarounds in the fifo_listen() routine.
     * Therefore we support both FIFOs and UNIX-domain sockets, so that the
     * user can choose whatever works best.
     * 
     * Well, I give up. Solaris UNIX-domain sockets still don't work properly,
     * so it will have to limp along with a streams-specific alternative.
     */
    if (stream == 0) {
	if (transport == 0)
	    msg_fatal("no transport type specified");
	if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
	    trigger_server_accept = trigger_server_accept_local;
	else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
	    trigger_server_accept = trigger_server_accept_fifo;
	else
	    msg_fatal("unsupported transport type: %s", transport);
    }

    /*
     * Optionally start the debugger on ourself.
     */
    if (debug_me)
	debug_process();

    /*
     * Traditionally, BSD select() can't handle multiple processes selecting
     * on the same socket, and wakes up every process in select(). See TCP/IP
     * Illustrated volume 2 page 532. We avoid select() collisions with an
     * external lock file.
     */
    if (stream == 0 && !alone) {
	lock_path = concatenate(DEF_PID_DIR, "/", transport,
				".", service_name, (char *) 0);
	why = vstring_alloc(1);
	if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
				      (struct stat *) 0, -1, -1, why)) == 0)
	    msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
	close_on_exec(vstream_fileno(trigger_server_lock), CLOSE_ON_EXEC);
	myfree(lock_path);
	vstring_free(why);
    }

    /*
     * Set up call-back info.
     */
    trigger_server_service = service;
    trigger_server_name = service_name;
    trigger_server_argv = argv + optind;

    /*
     * Run pre-jail initialization.
     */
    if (chdir(var_queue_dir) < 0)
	msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
    if (pre_init)
	pre_init(trigger_server_name, trigger_server_argv);

    /*
     * Optionally, restrict the damage that this process can do.
     */
    resolve_local_init();
    chroot_uid(root_dir, user_name);

    /*
     * Run post-jail initialization.
     */
    if (post_init)
	post_init(trigger_server_name, trigger_server_argv);

    /*
     * Are we running as a one-shot server with the client connection on
     * standard input?
     */
    if (stream != 0) {
	if ((len = read(vstream_fileno(stream), buf, sizeof(buf))) <= 0)
	    msg_fatal("read: %m");
	service(buf, len, trigger_server_name, trigger_server_argv);
	vstream_fflush(stream);
	trigger_server_exit();
    }

    /*
     * Running as a semi-resident server. Service connection requests.
     * Terminate when we have serviced a sufficient number of clients, when
     * no-one has been talking to us for a configurable amount of time, or
     * when the master process terminated abnormally.
     */
    if (var_idle_limit > 0)
	event_request_timer(trigger_server_timeout, (char *) 0, var_idle_limit);
    for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
	event_enable_read(fd, trigger_server_accept, CAST_INT_TO_CHAR_PTR(fd));
	close_on_exec(fd, CLOSE_ON_EXEC);
    }
    event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (char *) 0);
    close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
    watchdog = watchdog_create(1000, (WATCHDOG_FN) 0, (char *) 0);

    /*
     * The event loop, at last.
     */
    while (var_use_limit == 0 || use_count < var_use_limit) {
	if (trigger_server_lock != 0) {
	    watchdog_stop(watchdog);
	    if (myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
			MYFLOCK_OP_EXCLUSIVE) < 0)
		msg_fatal("select lock: %m");
	}
	watchdog_start(watchdog);
	delay = loop ? loop(trigger_server_name, trigger_server_argv) : -1;
	event_loop(delay);
    }
    trigger_server_exit();
}
Exemplo n.º 9
0
int CopyRegularFileNet(const char *source, const char *dest, off_t size,
                       bool encrypt, AgentConnection *conn)
{
    char *buf, workbuf[CF_BUFSIZE], cfchangedstr[265];
    const int buf_size = 2048;

    off_t n_read_total = 0;
    EVP_CIPHER_CTX crypto_ctx;

    /* We encrypt only for CLASSIC protocol. The TLS protocol is always over
     * encrypted layer, so it does not support encrypted (S*) commands. */
    encrypt = encrypt && conn->conn_info->protocol == CF_PROTOCOL_CLASSIC;

    if (encrypt)
    {
        return EncryptCopyRegularFileNet(source, dest, size, conn);
    }

    snprintf(cfchangedstr, 255, "%s%s", CF_CHANGEDSTR1, CF_CHANGEDSTR2);

    if ((strlen(dest) > CF_BUFSIZE - 20))
    {
        Log(LOG_LEVEL_ERR, "Filename too long");
        return false;
    }

    unlink(dest);                /* To avoid link attacks */

    int dd = safe_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, 0600);
    if (dd == -1)
    {
        Log(LOG_LEVEL_ERR,
            "Copy from server '%s' to destination '%s' failed (open: %s)",
            conn->this_server, dest, GetErrorStr());
        unlink(dest);
        return false;
    }



    workbuf[0] = '\0';
    int tosend = snprintf(workbuf, CF_BUFSIZE, "GET %d %s", buf_size, source);
    if (tosend <= 0 || tosend >= CF_BUFSIZE)
    {
        Log(LOG_LEVEL_ERR, "Failed to compose GET command for file %s",
            source);
        close(dd);
        return false;
    }

    /* Send proposition C0 */

    if (SendTransaction(conn->conn_info, workbuf, tosend, CF_DONE) == -1)
    {
        Log(LOG_LEVEL_ERR, "Couldn't send GET command");
        close(dd);
        return false;
    }

    buf = xmalloc(CF_BUFSIZE + sizeof(int));    /* Note CF_BUFSIZE not buf_size !! */

    Log(LOG_LEVEL_VERBOSE, "Copying remote file '%s:%s', expecting %jd bytes",
          conn->this_server, source, (intmax_t)size);

    n_read_total = 0;
    while (n_read_total < size)
    {
        int toget = MIN(size - n_read_total, buf_size);

        assert(toget != 0);

        /* Stage C1 - receive */
        int n_read;
        switch(conn->conn_info->protocol)
        {
        case CF_PROTOCOL_CLASSIC:
            n_read = RecvSocketStream(conn->conn_info->sd, buf, toget);
            break;
        case CF_PROTOCOL_TLS:
            n_read = TLSRecv(conn->conn_info->ssl, buf, toget);
            break;
        default:
            UnexpectedError("CopyRegularFileNet: ProtocolVersion %d!",
                            conn->conn_info->protocol);
            n_read = -1;
        }

        if (n_read <= 0)
        {
            /* This may happen on race conditions, where the file has shrunk
             * since we asked for its size in SYNCH ... STAT source */

            Log(LOG_LEVEL_ERR,
                "Error in client-server stream, has %s:%s shrunk? (code %d)",
                conn->this_server, source, n_read);
            close(dd);
            free(buf);
            return false;
        }

        /* If the first thing we get is an error message, break. */

        if ((n_read_total == 0) && (strncmp(buf, CF_FAILEDSTR, strlen(CF_FAILEDSTR)) == 0))
        {
            Log(LOG_LEVEL_INFO, "Network access to '%s:%s' denied",
                conn->this_server, source);
            close(dd);
            free(buf);
            return false;
        }

        if (strncmp(buf, cfchangedstr, strlen(cfchangedstr)) == 0)
        {
            Log(LOG_LEVEL_INFO, "Source '%s:%s' changed while copying",
                conn->this_server, source);
            close(dd);
            free(buf);
            return false;
        }


        /* Check for mismatch between encryption here and on server. */

        int value = -1;
        sscanf(buf, "t %d", &value);

        if ((value > 0) && (strncmp(buf + CF_INBAND_OFFSET, "BAD: ", 5) == 0))
        {
            Log(LOG_LEVEL_INFO, "Network access to cleartext '%s:%s' denied",
                conn->this_server, source);
            close(dd);
            free(buf);
            return false;
        }

        if (!FSWrite(dest, dd, buf, n_read))
        {
            Log(LOG_LEVEL_ERR,
                "Local disk write failed copying '%s:%s' to '%s'. (FSWrite: %s)",
                conn->this_server, source, dest, GetErrorStr());
            if (conn)
            {
                conn->error = true;
            }
            free(buf);
            unlink(dest);
            close(dd);
            FlushFileStream(conn->conn_info->sd, size - n_read_total);
            EVP_CIPHER_CTX_cleanup(&crypto_ctx);
            return false;
        }

        n_read_total += n_read;
    }

    /* If the file ends with a `hole', something needs to be written at
       the end.  Otherwise the kernel would truncate the file at the end
       of the last write operation. Write a null character and truncate
       it again.  */

    if (ftruncate(dd, n_read_total) < 0)
    {
        Log(LOG_LEVEL_ERR, "Copy failed (no space?) while copying '%s' from network '%s'",
            dest, GetErrorStr());
        free(buf);
        unlink(dest);
        close(dd);
        FlushFileStream(conn->conn_info->sd, size - n_read_total);
        return false;
    }

    close(dd);
    free(buf);
    return true;
}
int main (int argc,char *argv[])
{
	const char *progname,*filename = NULL,*device = NULL;
	int i,flags = FLAG_NONE;
	ssize_t result;
	size_t size,written;
	struct mtd_info_user mtd;
	struct erase_info_user erase;
	struct stat filestat;
	unsigned char src[BUFSIZE],dest[BUFSIZE];

	(progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]);

	/*********************
	 * parse cmd-line
	 *****************/

	for (;;) {
		int option_index = 0;
		static const char *short_options = "hv";
		static const struct option long_options[] = {
			{"help", no_argument, 0, 'h'},
			{"verbose", no_argument, 0, 'v'},
			{0, 0, 0, 0},
		};

		int c = getopt_long(argc, argv, short_options,
				long_options, &option_index);
		if (c == EOF) {
			break;
		}

		switch (c) {
			case 'h':
				flags |= FLAG_HELP;
				DEBUG("Got FLAG_HELP\n");
				break;
			case 'v':
				flags |= FLAG_VERBOSE;
				DEBUG("Got FLAG_VERBOSE\n");
				break;
			default:
				DEBUG("Unknown parameter: %s\n",argv[option_index]);
				showusage (progname,true);
		}
	}
	if (optind+2 == argc) {
		flags |= FLAG_FILENAME;
		filename = argv[optind];
		DEBUG("Got filename: %s\n",filename);

		flags |= FLAG_DEVICE;
		device = argv[optind+1];
		DEBUG("Got device: %s\n",device);
	}

	if (flags & FLAG_HELP || progname == NULL || device == NULL)
		showusage (progname,flags != FLAG_HELP);

	atexit (cleanup);

	/* get some info about the flash device */
	dev_fd = safe_open (device,O_SYNC | O_RDWR);
	if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0)
	{
		DEBUG("ioctl(): %m\n");
		log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n");
		exit (EXIT_FAILURE);
	}

	/* get some info about the file we want to copy */
	fil_fd = safe_open (filename,O_RDONLY);
	if (fstat (fil_fd,&filestat) < 0)
	{
		log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
		exit (EXIT_FAILURE);
	}

	/* does it fit into the device/partition? */
	if (filestat.st_size > mtd.size)
	{
		log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
		exit (EXIT_FAILURE);
	}

	/*****************************************************
	 * erase enough blocks so that we can write the file *
	 *****************************************************/

#warning "Check for smaller erase regions"

	erase.start = 0;
	erase.length = (filestat.st_size + mtd.erasesize - 1) / mtd.erasesize;
	erase.length *= mtd.erasesize;

	if (flags & FLAG_VERBOSE)
	{
		/* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */
		int blocks = erase.length / mtd.erasesize;
		erase.length = mtd.erasesize;
		log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks);
		for (i = 1; i <= blocks; i++)
		{
			log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks));
			if (ioctl (dev_fd,MEMERASE,&erase) < 0)
			{
				log_printf (LOG_NORMAL,"\n");
				log_printf (LOG_ERROR,
						"While erasing blocks 0x%.8x-0x%.8x on %s: %m\n",
						(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
				exit (EXIT_FAILURE);
			}
			erase.start += mtd.erasesize;
		}
		log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks);
	}
	else
	{
		/* if not, erase the whole chunk in one shot */
		if (ioctl (dev_fd,MEMERASE,&erase) < 0)
		{
			log_printf (LOG_ERROR,
					"While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n",
					(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
			exit (EXIT_FAILURE);
		}
	}
	DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);

	/**********************************
	 * write the entire file to flash *
	 **********************************/

	if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size));
	size = filestat.st_size;
	i = BUFSIZE;
	written = 0;
	while (size)
	{
		if (size < BUFSIZE) i = size;
		if (flags & FLAG_VERBOSE)
			log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)",
					KB (written + i),
					KB (filestat.st_size),
					PERCENTAGE (written + i,filestat.st_size));

		/* read from filename */
		safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);

		/* write to device */
		result = write (dev_fd,src,i);
		if (i != result)
		{
			if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n");
			if (result < 0)
			{
				log_printf (LOG_ERROR,
						"While writing data to 0x%.8x-0x%.8x on %s: %m\n",
						written,written + i,device);
				exit (EXIT_FAILURE);
			}
			log_printf (LOG_ERROR,
					"Short write count returned while writing to x%.8x-0x%.8x on %s: %d/%lu bytes written to flash\n",
					written,written + i,device,written + result,filestat.st_size);
			exit (EXIT_FAILURE);
		}

		written += i;
		size -= i;
	}
	if (flags & FLAG_VERBOSE)
		log_printf (LOG_NORMAL,
				"\rWriting data: %luk/%luk (100%%)\n",
				KB (filestat.st_size),
				KB (filestat.st_size));
	DEBUG("Wrote %d / %luk bytes\n",written,filestat.st_size);

	/**********************************
	 * verify that flash == file data *
	 **********************************/

	safe_rewind (fil_fd,filename);
	safe_rewind (dev_fd,device);
	size = filestat.st_size;
	i = BUFSIZE;
	written = 0;
	if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size));
	while (size)
	{
		if (size < BUFSIZE) i = size;
		if (flags & FLAG_VERBOSE)
			log_printf (LOG_NORMAL,
					"\rVerifying data: %dk/%luk (%lu%%)",
					KB (written + i),
					KB (filestat.st_size),
					PERCENTAGE (written + i,filestat.st_size));

		/* read from filename */
		safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);

		/* read from device */
		safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);

		/* compare buffers */
		if (memcmp (src,dest,i))
		{
			log_printf (LOG_ERROR,
					"File does not seem to match flash data. First mismatch at 0x%.8x-0x%.8x\n",
					written,written + i);
			exit (EXIT_FAILURE);
		}

		written += i;
		size -= i;
	}
	if (flags & FLAG_VERBOSE)
		log_printf (LOG_NORMAL,
				"\rVerifying data: %luk/%luk (100%%)\n",
				KB (filestat.st_size),
				KB (filestat.st_size));
	DEBUG("Verified %d / %luk bytes\n",written,filestat.st_size);

	exit (EXIT_SUCCESS);
}
Exemplo n.º 11
0
int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, AgentConnection *conn)
{
    int dd, blocksize = 2048, n_read = 0, towrite, plainlen, more = true, finlen, cnt = 0;
    int tosend, cipherlen = 0;
    char *buf, in[CF_BUFSIZE], out[CF_BUFSIZE], workbuf[CF_BUFSIZE], cfchangedstr[265];
    unsigned char iv[32] =
        { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
    long n_read_total = 0;
    EVP_CIPHER_CTX crypto_ctx;

    snprintf(cfchangedstr, 255, "%s%s", CF_CHANGEDSTR1, CF_CHANGEDSTR2);

    if ((strlen(dest) > CF_BUFSIZE - 20))
    {
        Log(LOG_LEVEL_ERR, "Filename too long");
        return false;
    }

    unlink(dest);                /* To avoid link attacks */

    if ((dd = safe_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, 0600)) == -1)
    {
        Log(LOG_LEVEL_ERR,
            "Copy from server '%s' to destination '%s' failed (open: %s)",
            conn->this_server, dest, GetErrorStr());
        unlink(dest);
        return false;
    }

    if (size == 0)
    {
        // No sense in copying an empty file
        close(dd);
        return true;
    }

    workbuf[0] = '\0';
    EVP_CIPHER_CTX_init(&crypto_ctx);

    snprintf(in, CF_BUFSIZE - CF_PROTO_OFFSET, "GET dummykey %s", source);
    cipherlen = EncryptString(conn->encryption_type, in, out, conn->session_key, strlen(in) + 1);
    snprintf(workbuf, CF_BUFSIZE, "SGET %4d %4d", cipherlen, blocksize);
    memcpy(workbuf + CF_PROTO_OFFSET, out, cipherlen);
    tosend = cipherlen + CF_PROTO_OFFSET;

/* Send proposition C0 - query */

    if (SendTransaction(conn->conn_info, workbuf, tosend, CF_DONE) == -1)
    {
        Log(LOG_LEVEL_ERR, "Couldn't send data. (SendTransaction: %s)", GetErrorStr());
        close(dd);
        return false;
    }

    buf = xmalloc(CF_BUFSIZE + sizeof(int));

    n_read_total = 0;

    while (more)
    {
        if ((cipherlen = ReceiveTransaction(conn->conn_info, buf, &more)) == -1)
        {
            free(buf);
            return false;
        }

        cnt++;

        /* If the first thing we get is an error message, break. */

        if ((n_read_total == 0) && (strncmp(buf + CF_INBAND_OFFSET, CF_FAILEDSTR, strlen(CF_FAILEDSTR)) == 0))
        {
            Log(LOG_LEVEL_INFO, "Network access to '%s:%s' denied", conn->this_server, source);
            close(dd);
            free(buf);
            return false;
        }

        if (strncmp(buf + CF_INBAND_OFFSET, cfchangedstr, strlen(cfchangedstr)) == 0)
        {
            Log(LOG_LEVEL_INFO, "Source '%s:%s' changed while copying", conn->this_server, source);
            close(dd);
            free(buf);
            return false;
        }

        EVP_DecryptInit_ex(&crypto_ctx, CfengineCipher(CfEnterpriseOptions()), NULL, conn->session_key, iv);

        if (!EVP_DecryptUpdate(&crypto_ctx, workbuf, &plainlen, buf, cipherlen))
        {
            close(dd);
            free(buf);
            return false;
        }

        if (!EVP_DecryptFinal_ex(&crypto_ctx, workbuf + plainlen, &finlen))
        {
            close(dd);
            free(buf);
            return false;
        }

        towrite = n_read = plainlen + finlen;

        n_read_total += n_read;

        if (!FSWrite(dest, dd, workbuf, towrite))
        {
            Log(LOG_LEVEL_ERR, "Local disk write failed copying '%s:%s' to '%s:%s'",
                conn->this_server, source, dest, GetErrorStr());
            if (conn)
            {
                conn->error = true;
            }
            free(buf);
            unlink(dest);
            close(dd);
            EVP_CIPHER_CTX_cleanup(&crypto_ctx);
            return false;
        }
    }

    /* If the file ends with a `hole', something needs to be written at
       the end.  Otherwise the kernel would truncate the file at the end
       of the last write operation. Write a null character and truncate
       it again.  */

    if (ftruncate(dd, n_read_total) < 0)
    {
        Log(LOG_LEVEL_ERR, "Copy failed (no space?) while copying '%s' from network '%s'",
            dest, GetErrorStr());
        free(buf);
        unlink(dest);
        close(dd);
        EVP_CIPHER_CTX_cleanup(&crypto_ctx);
        return false;
    }

    close(dd);
    free(buf);
    EVP_CIPHER_CTX_cleanup(&crypto_ctx);
    return true;
}
Exemplo n.º 12
0
MBOX   *mbox_open(const char *path, int flags, mode_t mode, struct stat * st,
		          uid_t chown_uid, gid_t chown_gid,
		          int lock_style, const char *def_dsn,
		          DSN_BUF *why)
{
    struct stat local_statbuf;
    MBOX   *mp;
    int     locked = 0;
    VSTREAM *fp;

    if (st == 0)
	st = &local_statbuf;

    /*
     * If this is a regular file, create a dotlock file. This locking method
     * does not work well over NFS, but it is better than some alternatives.
     * With NFS, creating files atomically is a problem, and a successful
     * operation can fail with EEXIST.
     * 
     * If filename.lock can't be created for reasons other than "file exists",
     * issue only a warning if the application says it is non-fatal. This is
     * for bass-awkward compatibility with existing installations that
     * deliver to files in non-writable directories.
     * 
     * We dot-lock the file before opening, so we must avoid doing silly things
     * like dot-locking /dev/null. Fortunately, deliveries to non-mailbox
     * files execute with recipient privileges, so we don't have to worry
     * about creating dotlock files in places where the recipient would not
     * be able to write.
     * 
     * Note: we use stat() to follow symlinks, because safe_open() allows the
     * target to be a root-owned symlink, and we don't want to create dotlock
     * files for /dev/null or other non-file objects.
     */
    if ((lock_style & MBOX_DOT_LOCK)
	&& (stat(path, st) < 0 || S_ISREG(st->st_mode))) {
	if (dot_lockfile(path, why->reason) == 0) {
	    locked |= MBOX_DOT_LOCK;
	} else if (errno == EEXIST) {
	    dsb_status(why, mbox_dsn(EAGAIN, def_dsn));
	    return (0);
	} else if (lock_style & MBOX_DOT_LOCK_MAY_FAIL) {
	    msg_warn("%s", vstring_str(why->reason));
	} else {
	    dsb_status(why, mbox_dsn(errno, def_dsn));
	    return (0);
	}
    }

    /*
     * Open or create the target file. In case of a privileged open, the
     * privileged user may be attacked with hard/soft link tricks in an
     * unsafe parent directory. In case of an unprivileged open, the mail
     * system may be attacked by a malicious user-specified path, or the
     * unprivileged user may be attacked with hard/soft link tricks in an
     * unsafe parent directory. Open non-blocking to fend off attacks
     * involving non-file targets.
     */
    if ((fp = safe_open(path, flags | O_NONBLOCK, mode, st,
			chown_uid, chown_gid, why->reason)) == 0) {
	dsb_status(why, mbox_dsn(errno, def_dsn));
	if (locked & MBOX_DOT_LOCK)
	    dot_unlockfile(path);
	return (0);
    }
    close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);

    /*
     * If this is a regular file, acquire kernel locks. flock() locks are not
     * intended to work across a network; fcntl() locks are supposed to work
     * over NFS, but in the real world, NFS lock daemons often have serious
     * problems.
     */
#define HUNKY_DORY(lock_mask, myflock_style) ((lock_style & (lock_mask)) == 0 \
         || deliver_flock(vstream_fileno(fp), (myflock_style), why->reason) == 0)

    if (S_ISREG(st->st_mode)) {
	if (HUNKY_DORY(MBOX_FLOCK_LOCK, MYFLOCK_STYLE_FLOCK)
	    && HUNKY_DORY(MBOX_FCNTL_LOCK, MYFLOCK_STYLE_FCNTL)) {
	    locked |= lock_style;
	} else {
	    dsb_status(why, mbox_dsn(errno, def_dsn));
	    if (locked & MBOX_DOT_LOCK)
		dot_unlockfile(path);
	    vstream_fclose(fp);
	    return (0);
	}
    }

    /*
     * Sanity check: reportedly, GNU POP3D creates a new mailbox file and
     * deletes the old one. This does not play well with software that opens
     * the mailbox first and then locks it, such as software that uses FCNTL
     * or FLOCK locks on open file descriptors (some UNIX systems don't use
     * dotlock files).
     * 
     * To detect that GNU POP3D deletes the mailbox file we look at the target
     * file hard-link count. Note that safe_open() guarantees a hard-link
     * count of 1, so any change in this count is a sign of trouble.
     */
    if (S_ISREG(st->st_mode)
	&& (fstat(vstream_fileno(fp), st) < 0 || st->st_nlink != 1)) {
	vstring_sprintf(why->reason, "target file status changed unexpectedly");
	dsb_status(why, mbox_dsn(EAGAIN, def_dsn));
	msg_warn("%s: file status changed unexpectedly", path);
	if (locked & MBOX_DOT_LOCK)
	    dot_unlockfile(path);
	vstream_fclose(fp);
	return (0);
    }
    mp = (MBOX *) mymalloc(sizeof(*mp));
    mp->path = mystrdup(path);
    mp->fp = fp;
    mp->locked = locked;
    return (mp);
}
Exemplo n.º 13
0
int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, AgentConnection *conn)
{
    int dd, blocksize = 2048, n_read = 0, plainlen, more = true, finlen, cnt = 0;
    int tosend, cipherlen = 0;
    char *buf, in[CF_BUFSIZE], out[CF_BUFSIZE], workbuf[CF_BUFSIZE], cfchangedstr[265];
    unsigned char iv[32] =
        { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
    EVP_CIPHER_CTX crypto_ctx;

    snprintf(cfchangedstr, 255, "%s%s", CF_CHANGEDSTR1, CF_CHANGEDSTR2);

    if ((strlen(dest) > CF_BUFSIZE - 20))
    {
        Log(LOG_LEVEL_ERR, "Filename too long");
        return false;
    }

    unlink(dest);                /* To avoid link attacks */

    if ((dd = safe_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, 0600)) == -1)
    {
        Log(LOG_LEVEL_ERR,
            "Copy from server '%s' to destination '%s' failed (open: %s)",
            conn->this_server, dest, GetErrorStr());
        unlink(dest);
        return false;
    }

    if (size == 0)
    {
        // No sense in copying an empty file
        close(dd);
        return true;
    }

    workbuf[0] = '\0';
    EVP_CIPHER_CTX_init(&crypto_ctx);

    snprintf(in, CF_BUFSIZE - CF_PROTO_OFFSET, "GET dummykey %s", source);
    cipherlen = EncryptString(out, sizeof(out), in, strlen(in) + 1, conn->encryption_type, conn->session_key);

    tosend = cipherlen + CF_PROTO_OFFSET;

    if(tosend > sizeof(workbuf))
    {
        ProgrammingError("EncryptCopyRegularFileNet: tosend (%d) > workbuf (%ld)",
                         tosend, sizeof(workbuf));
    }

    snprintf(workbuf, CF_BUFSIZE, "SGET %4d %4d", cipherlen, blocksize);
    memcpy(workbuf + CF_PROTO_OFFSET, out, cipherlen);

/* Send proposition C0 - query */

    if (SendTransaction(conn->conn_info, workbuf, tosend, CF_DONE) == -1)
    {
        Log(LOG_LEVEL_ERR, "Couldn't send data. (SendTransaction: %s)", GetErrorStr());
        close(dd);
        return false;
    }

    buf = xmalloc(CF_BUFSIZE + sizeof(int));

    bool   last_write_made_hole = false;
    size_t n_wrote_total        = 0;

    while (more)
    {
        if ((cipherlen = ReceiveTransaction(conn->conn_info, buf, &more)) == -1)
        {
            free(buf);
            return false;
        }

        cnt++;

        /* If the first thing we get is an error message, break. */

        if (n_wrote_total == 0 &&
            strncmp(buf + CF_INBAND_OFFSET, CF_FAILEDSTR, strlen(CF_FAILEDSTR)) == 0)
        {
            Log(LOG_LEVEL_INFO, "Network access to '%s:%s' denied", conn->this_server, source);
            close(dd);
            free(buf);
            return false;
        }

        if (strncmp(buf + CF_INBAND_OFFSET, cfchangedstr, strlen(cfchangedstr)) == 0)
        {
            Log(LOG_LEVEL_INFO, "Source '%s:%s' changed while copying", conn->this_server, source);
            close(dd);
            free(buf);
            return false;
        }

        EVP_DecryptInit_ex(&crypto_ctx, CfengineCipher(CfEnterpriseOptions()), NULL, conn->session_key, iv);

        if (!EVP_DecryptUpdate(&crypto_ctx, workbuf, &plainlen, buf, cipherlen))
        {
            close(dd);
            free(buf);
            return false;
        }

        if (!EVP_DecryptFinal_ex(&crypto_ctx, workbuf + plainlen, &finlen))
        {
            close(dd);
            free(buf);
            return false;
        }

        n_read = plainlen + finlen;

        bool w_ok = FileSparseWrite(dd, workbuf, n_read,
                                    &last_write_made_hole);
        if (!w_ok)
        {
            Log(LOG_LEVEL_ERR,
                "Local disk write failed copying '%s:%s' to '%s'",
                conn->this_server, source, dest);
            free(buf);
            unlink(dest);
            close(dd);
            conn->error = true;
            EVP_CIPHER_CTX_cleanup(&crypto_ctx);
            return false;
        }

        n_wrote_total += n_read;
    }

    const bool do_sync = false;

    bool ret = FileSparseClose(dd, dest, do_sync,
                               n_wrote_total, last_write_made_hole);
    if (!ret)
    {
        unlink(dest);
        free(buf);
        EVP_CIPHER_CTX_cleanup(&crypto_ctx);
        return false;
    }

    free(buf);
    EVP_CIPHER_CTX_cleanup(&crypto_ctx);
    return true;
}
Exemplo n.º 14
0
/* returns 1 on success, 0 on error */
int mutt_pipe_attachment (FILE *fp, BODY *b, const char *path, char *outfile)
{
  pid_t thepid;
  int out = -1;
  int rv = 0;
  
  if (outfile && *outfile)
    if ((out = safe_open (outfile, O_CREAT | O_EXCL | O_WRONLY)) < 0)
    {
      mutt_perror ("open");
      return 0;
    }

  mutt_endwin (NULL);

  if (fp)
  {
    /* recv case */

    STATE s;

    memset (&s, 0, sizeof (STATE));

    if (outfile && *outfile)
      thepid = mutt_create_filter_fd (path, &s.fpout, NULL, NULL, -1, out, -1);
    else
      thepid = mutt_create_filter (path, &s.fpout, NULL, NULL);

    if (thepid < 0)
    {
      mutt_perror _("Can't create filter");
      goto bail;
    }
    
    s.fpin = fp;
    mutt_decode_attachment (b, &s);
    safe_fclose (&s.fpout);
  }
  else
  {
    /* send case */

    FILE *ifp, *ofp;

    if ((ifp = fopen (b->filename, "r")) == NULL)
    {
      mutt_perror ("fopen");
      if (outfile && *outfile)
      {
	close (out);
	unlink (outfile);
      }
      return 0;
    }

    if (outfile && *outfile)
      thepid = mutt_create_filter_fd (path, &ofp, NULL, NULL, -1, out, -1);
    else
      thepid = mutt_create_filter (path, &ofp, NULL, NULL);

    if (thepid < 0)
    {
      mutt_perror _("Can't create filter");
      safe_fclose (&ifp);
      goto bail;
    }
    
    mutt_copy_stream (ifp, ofp);
    safe_fclose (&ofp);
    safe_fclose (&ifp);
  }

  rv = 1;
  
bail:
  
  if (outfile && *outfile)
    close (out);

  /*
   * check for error exit from child process
   */
  if (mutt_wait_filter (thepid) != 0)
    rv = 0;

  if (rv == 0 || option (OPTWAITKEY))
    mutt_any_key_to_continue (NULL);
  return rv;
}
Exemplo n.º 15
0
/* returns -1 on error, 0 or the return code from mutt_do_pager() on success */
int mutt_view_attachment (FILE *fp, BODY *a, int flag, HEADER *hdr,
			  ATTACHPTR **idx, short idxlen)
{
  char tempfile[_POSIX_PATH_MAX] = "";
  char pagerfile[_POSIX_PATH_MAX] = "";
  int is_message;
  int use_mailcap;
  int use_pipe = 0;
  int use_pager = 1;
  char type[STRING];
  char command[HUGE_STRING];
  char descrip[STRING];
  char *fname;
  rfc1524_entry *entry = NULL;
  int rc = -1;
  int unlink_tempfile = 0;
  
  is_message = mutt_is_message_type(a->type, a->subtype);
  if (WithCrypto && is_message && a->hdr && (a->hdr->security & ENCRYPT) &&
      !crypt_valid_passphrase(a->hdr->security))
    return (rc);
  use_mailcap = (flag == M_MAILCAP ||
		(flag == M_REGULAR && mutt_needs_mailcap (a)));
  snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);
  
  if (use_mailcap)
  {
    entry = rfc1524_new_entry (); 
    if (!rfc1524_mailcap_lookup (a, type, entry, 0))
    {
      if (flag == M_REGULAR)
      {
	/* fallback to view as text */
	rfc1524_free_entry (&entry);
	mutt_error _("No matching mailcap entry found.  Viewing as text.");
	flag = M_AS_TEXT;
	use_mailcap = 0;
      }
      else
	goto return_error;
    }
  }
  
  if (use_mailcap)
  {
    if (!entry->command)
    {
      mutt_error _("MIME type not defined.  Cannot view attachment.");
      goto return_error;
    }
    strfcpy (command, entry->command, sizeof (command));
    
    if (fp)
    {
      fname = safe_strdup (a->filename);
      mutt_sanitize_filename (fname, 1);
    }
    else
      fname = a->filename;

    if (rfc1524_expand_filename (entry->nametemplate, fname,
				 tempfile, sizeof (tempfile)))
    {
      if (fp == NULL && mutt_strcmp(tempfile, a->filename))
      {
	/* send case: the file is already there */
	if (safe_symlink (a->filename, tempfile) == -1)
	{
	  if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) == M_YES)
	    strfcpy (tempfile, a->filename, sizeof (tempfile));
	  else
	    goto return_error;
	}
	else
	  unlink_tempfile = 1;
      }
    }
    else if (fp == NULL) /* send case */
      strfcpy (tempfile, a->filename, sizeof (tempfile));
    
    if (fp)
    {
      /* recv case: we need to save the attachment to a file */
      FREE (&fname);
      if (mutt_save_attachment (fp, a, tempfile, 0, NULL) == -1)
	goto return_error;
      chmod (tempfile, 0400);
    }

    use_pipe = rfc1524_expand_command (a, tempfile, type,
				       command, sizeof (command));
    use_pager = entry->copiousoutput;
  }
  
  if (use_pager)
  {
    if (fp && !use_mailcap && a->filename)
    {
      /* recv case */
      strfcpy (pagerfile, a->filename, sizeof (pagerfile));
      mutt_adv_mktemp (pagerfile, sizeof(pagerfile));
    }
    else
      mutt_mktemp (pagerfile, sizeof (pagerfile));
  }
    
  if (use_mailcap)
  {
    pid_t thepid = 0;
    int tempfd = -1, pagerfd = -1;
    
    if (!use_pager)
      mutt_endwin (NULL);

    if (use_pager || use_pipe)
    {
      if (use_pager && ((pagerfd = safe_open (pagerfile, O_CREAT | O_EXCL | O_WRONLY)) == -1))
      {
	mutt_perror ("open");
	goto return_error;
      }
      if (use_pipe && ((tempfd = open (tempfile, 0)) == -1))
      {
	if(pagerfd != -1)
	  close(pagerfd);
	mutt_perror ("open");
	goto return_error;
      }

      if ((thepid = mutt_create_filter_fd (command, NULL, NULL, NULL,
					   use_pipe ? tempfd : -1, use_pager ? pagerfd : -1, -1)) == -1)
      {
	if(pagerfd != -1)
	  close(pagerfd);
	
	if(tempfd != -1)
	  close(tempfd);

	mutt_error _("Cannot create filter");
	goto return_error;
      }

      if (use_pager)
      {
	if (a->description)
	  snprintf (descrip, sizeof (descrip),
		    _("---Command: %-20.20s Description: %s"),
		    command, a->description);
	else
	  snprintf (descrip, sizeof (descrip),
		    _("---Command: %-30.30s Attachment: %s"), command, type);
      }

      if ((mutt_wait_filter (thepid) || (entry->needsterminal &&
	  option (OPTWAITKEY))) && !use_pager)
	mutt_any_key_to_continue (NULL);

      if (tempfd != -1)
	close (tempfd);
      if (pagerfd != -1)
	close (pagerfd);
    }
    else
    {
      /* interactive command */
      if (mutt_system (command) ||
	  (entry->needsterminal && option (OPTWAITKEY)))
	mutt_any_key_to_continue (NULL);
    }
  }
  else
  {
    /* Don't use mailcap; the attachment is viewed in the pager */

    if (flag == M_AS_TEXT)
    {
      /* just let me see the raw data */
      if (fp)
      {
	/* Viewing from a received message.
	 *
	 * Don't use mutt_save_attachment() because we want to perform charset
	 * conversion since this will be displayed by the internal pager.
	 */
	STATE decode_state;

	memset(&decode_state, 0, sizeof(decode_state));
	decode_state.fpout = safe_fopen(pagerfile, "w");
	if (!decode_state.fpout)
	{
	  dprint(1, (debugfile, "mutt_view_attachment:%d safe_fopen(%s) errno=%d %s\n", __LINE__, pagerfile, errno, strerror(errno)));
	  mutt_perror(pagerfile);
	  mutt_sleep(1);
	  goto return_error;
	}
	decode_state.fpin = fp;
	decode_state.flags = M_CHARCONV;
	mutt_decode_attachment(a, &decode_state);
	if (fclose(decode_state.fpout) == EOF)
	  dprint(1, (debugfile, "mutt_view_attachment:%d fclose errno=%d %s\n", __LINE__, pagerfile, errno, strerror(errno)));
      }
      else
      {
	/* in compose mode, just copy the file.  we can't use
	 * mutt_decode_attachment() since it assumes the content-encoding has
	 * already been applied
	 */
	if (mutt_save_attachment(fp, a, pagerfile, 0, NULL))
	  goto return_error;
      }
    }
    else
    {
      /* Use built-in handler */
      set_option (OPTVIEWATTACH); /* disable the "use 'v' to view this part"
				   * message in case of error */
      if (mutt_decode_save_attachment (fp, a, pagerfile, M_DISPLAY, 0))
      {
	unset_option (OPTVIEWATTACH);
	goto return_error;
      }
      unset_option (OPTVIEWATTACH);
    }
    
    if (a->description)
      strfcpy (descrip, a->description, sizeof (descrip));
    else if (a->filename)
      snprintf (descrip, sizeof (descrip), _("---Attachment: %s: %s"),
	  a->filename, type);
    else
      snprintf (descrip, sizeof (descrip), _("---Attachment: %s"), type);
  }
  
  /* We only reach this point if there have been no errors */

  if (use_pager)
  {
    pager_t info;
    
    memset (&info, 0, sizeof (info));
    info.fp = fp;
    info.bdy = a;
    info.ctx = Context;
    info.idx = idx;
    info.idxlen = idxlen;
    info.hdr = hdr;

    rc = mutt_do_pager (descrip, pagerfile,
			M_PAGER_ATTACHMENT | (is_message ? M_PAGER_MESSAGE : 0), &info);
    *pagerfile = '\0';
  }
  else
    rc = 0;

  return_error:
  
  if (entry)
    rfc1524_free_entry (&entry);
  if (fp && tempfile[0])
  {
    /* Restore write permission so mutt_unlink can open the file for writing */
    chmod(tempfile, 0600);
    mutt_unlink (tempfile);
  }
  else if (unlink_tempfile)
    unlink(tempfile);

  if (pagerfile[0])
    mutt_unlink (pagerfile);

  return rc;
}