Beispiel #1
0
static void
drop_privileges(struct passwd *pw)
{
	int pair[2] = { -1, -1 };

	if (geteuid())
		fatalx("in order to drop privileges you need to have them!");

	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) == -1)
		fatal("socketpair(2)");

	switch ((privileged_pid = fork())) {
	case -1:
		fatal("forking unprivileged process");
		/* NOTREACHED */
	case 0:
		privsep_init(pair[0], pair[1]);
		setproctitle("[priv]");

		exit(privileged_main());
		/* NOTREACHED */
	}
	privsep_init(pair[1], pair[0]);
	setproctitle("dhcp engine");

	if (chroot(CHROOT_PATH) == -1)
		fatal("chroot(" CHROOT_PATH ") failed");
	if (chdir("/") == -1)
		fatal("chdir inside chroot failed");

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		fatal("can't drop privileges to " UNPRIVILEGED_USER);
}
Beispiel #2
0
int
main(int argc, char *argv[])
{
	unsigned char msg[MSG_SIZE];
	char pidstr[16];
	ssize_t ret;
	int c, log_method;
	char *logfile, *pidfile;
	sigset_t oset, nset;
	int facility, fd;
	char *username = NULL;
	char *chrootdir = NULL;
	int singleprocess = 0;
#ifdef HAVE_GETOPT_LONG
	int opt_idx;
#endif
    /* BEGIN: Added by z67728, 2009/10/19 */
    FILE * pidfp = NULL;
    int    pid   = 0;
    /* END:   Added by z67728, 2009/10/19 */

    /*start: 用于查询组件版本号(dns atpv),请不要修改或删除*/
    /*if ((argc == 2) && (NULL != argv[1]) && (0 == strcmp(argv[1],ATP_VERSION_CMD_KEY)))
    {
       printf("\r\n%s.\n", RADVD_MODULE_VERSION);    	    		
       exit(0);
    }*/
    /*end */ 
    
	pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];

	srand((unsigned int)time(NULL));

	log_method = L_STDERR_SYSLOG;
    /*BEGIN PN:2071008409 l00170266 for var problem modify 20120725 */
#define RADVD_LOG (ROUTER_VARPATH_PREFIX "/radvd/radvd.log")
#define RADVD_CONF (ROUTER_VARPATH_PREFIX "/radvd/radvd.conf")
#define RADVD_PID (ROUTER_VARPATH_PREFIX "/radvd/radvd.pid")
	logfile = RADVD_LOG;
	conf_file = RADVD_CONF;
	facility = LOG_FACILITY;
	pidfile = RADVD_PID;
    /*END PN:2071008409 l00170266 for var problem modify 20120725 */

	/* parse args */
#ifdef HAVE_GETOPT_LONG
	while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhs", prog_opt, &opt_idx)) > 0)
#else
	while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhs")) > 0)
#endif
	{
		switch (c) {
		case 'C':
			conf_file = optarg;
			break;
		case 'd':
			set_debuglevel(atoi(optarg));
			break;
		case 'f':
			facility = atoi(optarg);
			break;
		case 'l':
			logfile = optarg;
			break;
		case 'p':
			pidfile = optarg;
			break;
		case 'm':
			if (!strcmp(optarg, "syslog"))
			{
				log_method = L_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr_syslog"))
			{
				log_method = L_STDERR_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr"))
			{
				log_method = L_STDERR;
			}
			else if (!strcmp(optarg, "logfile"))
			{
				log_method = L_LOGFILE;
			}
			else if (!strcmp(optarg, "none"))
			{
				log_method = L_NONE;
			}
			else
			{
				fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
				exit(1);
			}
			break;
		case 't':
			chrootdir = strdup(optarg);
			break;
		case 'u':
			username = strdup(optarg);
			break;
		case 'v':
            /* BEGIN 3061302357 y00188255 2013-6-28  Modified */
			//version();
			printf("%s\n", RADVD_MODULE_VERSION);
                    printf("BUILTTIME is: %s %s\n",__DATE__,__TIME__);
			exit(1);
			/* END 3061302357 y00188255 2013-6-28  Modified */
			break;
		case 's':
			singleprocess = 1;
			break;
		case 'h':
			usage();
#ifdef HAVE_GETOPT_LONG
		case ':':
			fprintf(stderr, "%s: option %s: parameter expected\n", pname,
				prog_opt[opt_idx].name);
			exit(1);
#endif
		case '?':
			exit(1);
		}
	}

	if (chrootdir) {
		if (!username) {
			fprintf(stderr, "Chroot as root is not safe, exiting\n");
			exit(1);
		}
		
		if (chroot(chrootdir) == -1) {
			perror("chroot");
			exit (1);
		}
		
		if (chdir("/") == -1) {
			perror("chdir");
			exit (1);
		}
		/* username will be switched later */
	}
	
	if (log_open(log_method, pname, logfile, facility) < 0)
		exit(1);

	flog(LOG_INFO, "version %s started", VERSION);

	/* get a raw socket for sending and receiving ICMPv6 messages */
	sock = open_icmpv6_socket();
	if (sock < 0)
		exit(1);

#if 0 
	/* check that 'other' cannot write the file
         * for non-root, also that self/own group can't either
         */
	if (check_conffile_perm(username, conf_file) < 0) {
		if (get_debuglevel() == 0)
			exit(1);
		else
			flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
	}
	
	/* if we know how to do it, check whether forwarding is enabled */
	if (check_ip6_forwarding()) {
		if (get_debuglevel() == 0) {
			flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting");
			exit(1);
		}
		else
			flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway.");
	}
#endif

	/* parse config file */
	if (readin_config(conf_file) < 0){
        if ( 0 != unlink(pidfile) ){
            printf("\r\n Delete %s meet error. error : %s .",pidfile,strerror(errno));
        }
		exit(1);
    }   

	/* drop root privileges if requested. */
	if (username) {
		if (!singleprocess) {
		 	dlog(LOG_DEBUG, 3, "Initializing privsep");
		 	if (privsep_init() < 0)
				flog(LOG_WARNING, "Failed to initialize privsep.");
		}

		if (drop_root_privileges(username) < 0)
			exit(1);
	}
#if 0
	if ((fd = open(pidfile, O_RDONLY, 0)) > 0)
	{
		ret = read(fd, pidstr, sizeof(pidstr) - 1);
		if (ret < 0)
		{
			flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno));
			exit(1);
		}
		pidstr[ret] = '\0';
		if (!kill((pid_t)atol(pidstr), 0))
		{
			flog(LOG_ERR, "radvd already running, terminating.");
			exit(1);
		}
		close(fd);
		fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
	}
	else	/* FIXME: not atomic if pidfile is on an NFS mounted volume */
		fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);

	if (fd < 0)
	{
		flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno));
		exit(1);
	}
#endif	
	/*
	 * okay, config file is read in, socket and stuff is setup, so
	 * lets fork now...
	 */
#if 0 
	if (get_debuglevel() == 0) {

		/* Detach from controlling terminal */
		if (daemon(0, 0) < 0)
			perror("daemon");

		/* close old logfiles, including stderr */
		log_close();
		
		/* reopen logfiles, but don't log to stderr unless explicitly requested */
		if (log_method == L_STDERR_SYSLOG)
			log_method = L_SYSLOG;
		if (log_open(log_method, pname, logfile, facility) < 0)
			exit(1);

	}
#endif

	/*
	 *	config signal handlers, also make sure ALRM isn't blocked and raise a warning if so
	 *      (some stupid scripts/pppd appears to do this...)
	 */
	sigemptyset(&nset);
	sigaddset(&nset, SIGALRM);
	sigprocmask(SIG_UNBLOCK, &nset, &oset);
	if (sigismember(&oset, SIGALRM))
		flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong.");

	signal(SIGHUP, sighup_handler);
	signal(SIGTERM, sigterm_handler);
	signal(SIGINT, sigint_handler);
    /* BEGIN: Added by z67728, 2009/11/3 */    
    signal(SIGUSR1, sigdebug_handler);
    signal(SIGUSR2, sigprefixchg_handler);
    /* END:   Added by z67728, 2009/11/3 */
    
#if 0
	snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid());
	
	write(fd, pidstr, strlen(pidstr));
	
	close(fd);
#endif

    /*BEGIN PN:2071008409 l00170266 for var problem modify 20120725 */
#define RADVD_READTEST (ROUTER_VARPATH_PREFIX "/radvd/readtest")
    if ( 0 == access(RADVD_READTEST,F_OK) )
    /*END PN:2071008409 l00170266 for var problem modify 20120725 */
    {
        /* Ready test */
        g_iReadTestFlag = 1;
    }

    pid = getpid();
	if ((pidfp = fopen(pidfile, "w")) != NULL) {
		fwrite(&pid,1,4,pidfp);
		fclose(pidfp);
	}
    
	config_interface();
	kickoff_adverts();

	/* enter loop */

	for (;;)
	{
		int len = 0, hoplimit = 0;
		struct sockaddr_in6 rcv_addr;
		struct in6_pktinfo *pkt_info = NULL;
		
		len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
		if (len > 0) {
			process(sock, IfaceList, msg, len, 
				&rcv_addr, pkt_info, hoplimit);
        }      

		if (sigterm_received || sigint_received) {
			stop_adverts();
			break;
		}

		if (sighup_received)
		{
		    if ( 1 == g_iPrefixChgeFlag )
		    {		        
    		    disable_oldprefix();
		    }

            reload_config();	
            
			sighup_received = 0;
            g_iPrefixChgeFlag = 0;
		}
	}

	unlink(pidfile);
	exit(0);
}
Beispiel #3
0
int main(int argc, char *argv[])
{
    opt_t opt;
    int retval = 0;
    const char *m;


    /*
     * Initialize.
     */
    err_init(xbasename(argv[0]));       /* init err package */

    /*
     *  If running setuid, fork a child to handle 
     *   all privileged operations and drop privs in this process.
     */
    privsep_init();

    /*
     * Seed options with default values:
     */
    opt_default(&opt, argv[0]);

    /*
     * Override defaults with environment
     */
    opt_env(&opt);

    /*
     * Process any options that need to be handled early:
     */
    opt_args_early(&opt, argc, argv);

    /*
     *  Load static or dynamic pdsh modules
     */
    mod_init();
    /*
     *  Allow module directory to be overridden, but not when
     *   running as root or setuid. (This is mainly for testing...)
     */
    if (!(m = getenv ("PDSH_MODULE_DIR")) ||
          getuid() == 0 ||
          getuid() != geteuid())
        m = pdsh_module_dir;
    if (mod_load_modules(m, &opt) < 0)
        errx("%p: Couldn't load any pdsh modules\n");

    /*
     * Handle options.
     */
    opt_args(&opt, argc, argv); /* override with command line           */

    if (opt_verify(&opt)) {     /* verify options, print errors         */
        /*
         * Do the work.
         */
        if (opt.info_only)      /* display info only */
            opt_list(&opt);
        else if (pdsh_personality() == PCP && opt.pcp_server) 
            retval = (_pcp_remote_server (&opt) < 0);
        else if (pdsh_personality() == PCP && opt.pcp_client)
            retval = (_pcp_remote_client (&opt) < 0);
        else if (pdsh_personality() == PCP || opt.cmd != NULL)
            retval = dsh(&opt); /* single dsh/pcp command */
        else                    /* prompt loop */
            _interactive_dsh(&opt);
    } else {
        retval = 1;
    }

    mod_exit(); 

    /*
     * Clean up.
     */
    privsep_fini();
    opt_free(&opt);             /* free heap storage in opt struct */
    err_cleanup();

    return retval;
}
Beispiel #4
0
int
main(int argc, char *argv[])
{
	unsigned char msg[MSG_SIZE];
	char pidstr[16];
	ssize_t ret;
	int c, log_method;
	char *logfile, *pidfile;
	sigset_t oset, nset;
	int facility, fd;
	char *username = NULL;
	char *chrootdir = NULL;
	int singleprocess = 0;
#ifdef HAVE_GETOPT_LONG
	int opt_idx;
#endif

	pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];

	srand((unsigned int)time(NULL));

	log_method = L_STDERR_SYSLOG;
	logfile = PATH_RADVD_LOG;
	conf_file = PATH_RADVD_CONF;
	facility = LOG_FACILITY;
	pidfile = PATH_RADVD_PID;

	/* parse args */
#ifdef HAVE_GETOPT_LONG
	/* Add option to show advertise real lifetime */
	/* while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhs", prog_opt, &opt_idx)) > 0) */
	while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhsD", prog_opt, &opt_idx)) > 0)
#else
	/* Add option to show advertise real lifetime */
	/* while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhs")) > 0) */
	while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhsD")) > 0)
#endif
	{
		switch (c) {
		case 'C':
			conf_file = optarg;
			break;
		case 'd':
			set_debuglevel(atoi(optarg));
			break;
		case 'f':
			facility = atoi(optarg);
			break;
		case 'l':
			logfile = optarg;
			break;
		case 'p':
			pidfile = optarg;
			break;
		case 'm':
			if (!strcmp(optarg, "syslog"))
			{
				log_method = L_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr_syslog"))
			{
				log_method = L_STDERR_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr"))
			{
				log_method = L_STDERR;
			}
			else if (!strcmp(optarg, "logfile"))
			{
				log_method = L_LOGFILE;
			}
			else if (!strcmp(optarg, "none"))
			{
				log_method = L_NONE;
			}
			else
			{
				fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
				exit(1);
			}
			break;
		case 't':
			chrootdir = strdup(optarg);
			break;
		case 'u':
			username = strdup(optarg);
			break;
		case 'v':
			version();
			break;
		case 's':
			singleprocess = 1;
			break;
		/* Add option to show advertise dynamic lifetime */
		case 'D':
			use_dynamic_lifetime = 1;
			break;
		case 'h':
			usage();
#ifdef HAVE_GETOPT_LONG
		case ':':
			fprintf(stderr, "%s: option %s: parameter expected\n", pname,
				prog_opt[opt_idx].name);
			exit(1);
#endif
		case '?':
			exit(1);
		}
	}

	if (chrootdir) {
		if (!username) {
			fprintf(stderr, "Chroot as root is not safe, exiting\n");
			exit(1);
		}
		
		if (chroot(chrootdir) == -1) {
			perror("chroot");
			exit (1);
		}
		
		if (chdir("/") == -1) {
			perror("chdir");
			exit (1);
		}
		/* username will be switched later */
	}
	
	if (log_open(log_method, pname, logfile, facility) < 0)
		exit(1);

	flog(LOG_INFO, "version %s started", VERSION);

	/* get a raw socket for sending and receiving ICMPv6 messages */
	sock = open_icmpv6_socket();
	if (sock < 0)
		exit(1);

	/* check that 'other' cannot write the file
         * for non-root, also that self/own group can't either
         */
	if (check_conffile_perm(username, conf_file) < 0) {
		if (get_debuglevel() == 0)
			exit(1);
		else
			flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
	}
	
	/* if we know how to do it, check whether forwarding is enabled */
	if (check_ip6_forwarding()) {
		if (get_debuglevel() == 0) {
			flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting");
			exit(1);
		}
		else
			flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway.");
	}

	/* parse config file */
	if (readin_config(conf_file) < 0)
		exit(1);

	/* drop root privileges if requested. */
	if (username) {
		if (!singleprocess) {
		 	dlog(LOG_DEBUG, 3, "Initializing privsep");
		 	if (privsep_init() < 0)
				flog(LOG_WARNING, "Failed to initialize privsep.");
		}

		if (drop_root_privileges(username) < 0)
			exit(1);
	}

	if ((fd = open(pidfile, O_RDONLY, 0)) > 0)
	{
		ret = read(fd, pidstr, sizeof(pidstr) - 1);
		if (ret < 0)
		{
			flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno));
			exit(1);
		}
		pidstr[ret] = '\0';
		if (!kill((pid_t)atol(pidstr), 0))
		{
			flog(LOG_ERR, "radvd already running, terminating.");
			exit(1);
		}
		close(fd);
		fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
	}
	else	/* FIXME: not atomic if pidfile is on an NFS mounted volume */
		fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);

	if (fd < 0)
	{
		flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno));
		exit(1);
	}
	
	/*
	 * okay, config file is read in, socket and stuff is setup, so
	 * lets fork now...
	 */

	if (get_debuglevel() == 0) {

		/* Detach from controlling terminal */
		if (daemon(0, 0) < 0)
			perror("daemon");

		/* close old logfiles, including stderr */
		log_close();
		
		/* reopen logfiles, but don't log to stderr unless explicitly requested */
		if (log_method == L_STDERR_SYSLOG)
			log_method = L_SYSLOG;
		if (log_open(log_method, pname, logfile, facility) < 0)
			exit(1);

	}

	/*
	 *	config signal handlers, also make sure ALRM isn't blocked and raise a warning if so
	 *      (some stupid scripts/pppd appears to do this...)
	 */
	sigemptyset(&nset);
	sigaddset(&nset, SIGALRM);
	sigprocmask(SIG_UNBLOCK, &nset, &oset);
	if (sigismember(&oset, SIGALRM))
		flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong.");

	signal(SIGHUP, sighup_handler);
	signal(SIGTERM, sigterm_handler);
	signal(SIGINT, sigint_handler);
	signal(SIGUSR1, sigusr1_handler);	

	snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid());
	
	write(fd, pidstr, strlen(pidstr));
	
	close(fd);

	config_interface();
	/* Record the time for first advertisement */
	set_initial_advert_time();
	kickoff_adverts();

	/* enter loop */

	for (;;)
	{
		int len, hoplimit;
		struct sockaddr_in6 rcv_addr;
		struct in6_pktinfo *pkt_info = NULL;
		
		len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
		if (len > 0)
			process(sock, IfaceList, msg, len, 
				&rcv_addr, pkt_info, hoplimit);

		if (sigterm_received || sigint_received) {
			stop_adverts();
			
			/* WNR3500L TD192, Per Netgear spec, 
			 * need to send RA for 3 times before termination.
			 */
			usleep(200000);
			stop_adverts();
			usleep(200000);
			stop_adverts();

			break;
		}

		if (sighup_received)
		{
			reload_config();		
			sighup_received = 0;
		}
		/* Reset the initial advertisement time to now */
		/* This should happen after a successful IADP renew */
		if (sigusr1_received)
		{
			set_initial_advert_time();
			sigusr1_received = 0;
		}
	}
	
	unlink(pidfile);
	exit(0);
}
Beispiel #5
0
int
session(void)
{
	fd_set rfds;
	struct timeval *timeout;
	int error;
	struct myaddrs *p;
	char pid_file[MAXPATHLEN];
	FILE *fp;
	pid_t racoon_pid = 0;
	int i;

	/* initialize schedular */
	sched_init();

	init_signal();

#ifdef ENABLE_ADMINPORT
	if (admin_init() < 0)
		exit(1);
#endif

	initmyaddr();

	if (isakmp_init() < 0)
		exit(1);

	initfds();

#ifdef ENABLE_NATT
	natt_keepalive_init ();
#endif

	if (privsep_init() != 0)
		exit(1);

	for (i = 0; i <= NSIG; i++)
		sigreq[i] = 0;

	/* write .pid file */
	racoon_pid = getpid();
	if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) 
		strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN);
	else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') 
		strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
	else {
		strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN);
		strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN);
	} 
	fp = fopen(pid_file, "w");
	if (fp) {
		if (fchmod(fileno(fp),
			S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
			syslog(LOG_ERR, "%s", strerror(errno));
			fclose(fp);
			exit(1);
		}
		fprintf(fp, "%ld\n", (long)racoon_pid);
		fclose(fp);
	} else {
		plog(LLV_ERROR, LOCATION, NULL,
			"cannot open %s", pid_file);
	}

	while (1) {
		if (dying)
			rfds = maskdying;
		else
			rfds = mask0;

		/*
		 * asynchronous requests via signal.
		 * make sure to reset sigreq to 0.
		 */
		check_sigreq();

		/* scheduling */
		timeout = schedular();

		error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout);
		if (error < 0) {
			switch (errno) {
			case EINTR:
				continue;
			default:
				plog(LLV_ERROR, LOCATION, NULL,
					"failed to select (%s)\n",
					strerror(errno));
				return -1;
			}
			/*NOTREACHED*/
		}

#ifdef ENABLE_ADMINPORT
		if ((lcconf->sock_admin != -1) &&
		    (FD_ISSET(lcconf->sock_admin, &rfds)))
			admin_handler();
#endif

		for (p = lcconf->myaddrs; p; p = p->next) {
			if (!p->addr)
				continue;
			if (FD_ISSET(p->sock, &rfds))
				isakmp_handler(p->sock);
		}

		if (FD_ISSET(lcconf->sock_pfkey, &rfds))
			pfkey_handler();

		if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) {
			if (update_myaddrs() && lcconf->autograbaddr)
				sched_new(5, check_rtsock, NULL);
			initfds();
		}
	}
}
Beispiel #6
0
int
main(int argc, char *argv[])
{
	char pidstr[16];
	ssize_t ret;
	int c, log_method;
	char *logfile, *pidfile;
	int facility, fd;
	char *username = NULL;
	char *chrootdir = NULL;
	int configtest = 0;
	int singleprocess = 0;
#ifdef HAVE_GETOPT_LONG
	int opt_idx;
#endif

	pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];

	srand((unsigned int)time(NULL));

	log_method = L_STDERR_SYSLOG;
	logfile = PATH_RADVD_LOG;
	conf_file = PATH_RADVD_CONF;
	facility = LOG_FACILITY;
	pidfile = PATH_RADVD_PID;

	/* parse args */
#define OPTIONS_STR "d:C:l:m:p:t:u:vhcs"
#ifdef HAVE_GETOPT_LONG
	while ((c = getopt_long(argc, argv, OPTIONS_STR, prog_opt, &opt_idx)) > 0)
#else
	while ((c = getopt(argc, argv, OPTIONS_STR)) > 0)
#endif
	{
		switch (c) {
		case 'C':
			conf_file = optarg;
			break;
		case 'd':
			set_debuglevel(atoi(optarg));
			break;
		case 'f':
			facility = atoi(optarg);
			break;
		case 'l':
			logfile = optarg;
			break;
		case 'p':
			pidfile = optarg;
			break;
		case 'm':
			if (!strcmp(optarg, "syslog"))
			{
				log_method = L_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr_syslog"))
			{
				log_method = L_STDERR_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr"))
			{
				log_method = L_STDERR;
			}
			else if (!strcmp(optarg, "logfile"))
			{
				log_method = L_LOGFILE;
			}
			else if (!strcmp(optarg, "none"))
			{
				log_method = L_NONE;
			}
			else
			{
				fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
				exit(1);
			}
			break;
		case 't':
			chrootdir = strdup(optarg);
			break;
		case 'u':
			username = strdup(optarg);
			break;
		case 'v':
			version();
			break;
		case 'c':
			configtest = 1;
			break;
		case 's':
			singleprocess = 1;
			break;
		case 'h':
			usage();
#ifdef HAVE_GETOPT_LONG
		case ':':
			fprintf(stderr, "%s: option %s: parameter expected\n", pname,
				prog_opt[opt_idx].name);
			exit(1);
#endif
		case '?':
			exit(1);
		}
	}

	if (chrootdir) {
		if (!username) {
			fprintf(stderr, "Chroot as root is not safe, exiting\n");
			exit(1);
		}

		if (chroot(chrootdir) == -1) {
			perror("chroot");
			exit (1);
		}

		if (chdir("/") == -1) {
			perror("chdir");
			exit (1);
		}
		/* username will be switched later */
	}

	if (configtest) {
		log_method = L_STDERR;
	}

	if (log_open(log_method, pname, logfile, facility) < 0) {
		perror("log_open");
		exit(1);
	}

	if (!configtest) {
		flog(LOG_INFO, "version %s started", VERSION);
	}

	/* get a raw socket for sending and receiving ICMPv6 messages */
	sock = open_icmpv6_socket();
	if (sock < 0) {
		perror("open_icmpv6_socket");
		exit(1);
	}

	/* check that 'other' cannot write the file
         * for non-root, also that self/own group can't either
         */
	if (check_conffile_perm(username, conf_file) < 0) {
		if (get_debuglevel() == 0) {
			flog(LOG_ERR, "Exiting, permissions on conf_file invalid.\n");
			exit(1);
		}
		else
			flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
	}

	/* if we know how to do it, check whether forwarding is enabled */
	if (check_ip6_forwarding()) {
		flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway.");
	}

	/* parse config file */
	if (readin_config(conf_file) < 0) {
		flog(LOG_ERR, "Exiting, failed to read config file.\n");
		exit(1);
	}

	if (configtest) {
		fprintf(stderr, "Syntax OK\n");
		exit(0);
	}

	/* drop root privileges if requested. */
	if (username) {
		if (!singleprocess) {
		 	dlog(LOG_DEBUG, 3, "Initializing privsep");
		 	if (privsep_init() < 0)
				flog(LOG_WARNING, "Failed to initialize privsep.");
		}

		if (drop_root_privileges(username) < 0) {
			perror("drop_root_privileges");
			exit(1);
		}
	}

	if ((fd = open(pidfile, O_RDONLY, 0)) > 0)
	{
		ret = read(fd, pidstr, sizeof(pidstr) - 1);
		if (ret < 0)
		{
			flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno));
			exit(1);
		}
		pidstr[ret] = '\0';
		if (!kill((pid_t)atol(pidstr), 0))
		{
			flog(LOG_ERR, "radvd already running, terminating.");
			exit(1);
		}
		close(fd);
		fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
	}
	else	/* FIXME: not atomic if pidfile is on an NFS mounted volume */
		fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);

	if (fd < 0)
	{
		flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno));
		exit(1);
	}

	/*
	 * okay, config file is read in, socket and stuff is setup, so
	 * lets fork now...
	 */

	if (get_debuglevel() == 0) {

		/* Detach from controlling terminal */
		if (daemon(0, 0) < 0)
			perror("daemon");

		/* close old logfiles, including stderr */
		log_close();

		/* reopen logfiles, but don't log to stderr unless explicitly requested */
		if (log_method == L_STDERR_SYSLOG)
			log_method = L_SYSLOG;
		if (log_open(log_method, pname, logfile, facility) < 0) {
			perror("log_open");
			exit(1);
		}

	}

	/*
	 *	config signal handlers
	 */
	signal(SIGHUP, sighup_handler);
	signal(SIGTERM, sigterm_handler);
	signal(SIGINT, sigint_handler);
	signal(SIGUSR1, sigusr1_handler);

	snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid());

	ret = write(fd, pidstr, strlen(pidstr));
	if (ret != strlen(pidstr))
	{
		flog(LOG_ERR, "cannot write radvd pid file, terminating: %s", strerror(errno));
		exit(1);
	}

	close(fd);

	config_interface();
	kickoff_adverts();
	main_loop();
	stop_adverts();
	unlink(pidfile);

	return 0;
}
Beispiel #7
0
int main(int argc, char *argv[])
{
	int c;
	int log_method = L_STDERR_SYSLOG;
	char *logfile = PATH_RADVD_LOG;
	int facility = LOG_FACILITY;
	char *username = NULL;
	char *chrootdir = NULL;
	int configtest = 0;
	int daemonize = 1;

	char const *pname = ((pname = strrchr(argv[0], '/')) != NULL) ? pname + 1 : argv[0];

	srand((unsigned int)time(NULL));

	char const *conf_path = PATH_RADVD_CONF;
	char const *daemon_pid_file_ident = PATH_RADVD_PID;

	/* parse args */
#define OPTIONS_STR "d:C:l:m:p:t:u:vhcn"
#ifdef HAVE_GETOPT_LONG
	int opt_idx;
	while ((c = getopt_long(argc, argv, OPTIONS_STR, prog_opt, &opt_idx)) > 0)
#else
	while ((c = getopt(argc, argv, OPTIONS_STR)) > 0)
#endif
	{
		switch (c) {
		case 'C':
			conf_path = optarg;
			break;
		case 'd':
			set_debuglevel(atoi(optarg));
			break;
		case 'f':
			facility = atoi(optarg);
			break;
		case 'l':
			logfile = optarg;
			break;
		case 'p':
			daemon_pid_file_ident = optarg;
			break;
		case 'm':
			if (!strcmp(optarg, "syslog")) {
				log_method = L_SYSLOG;
			} else if (!strcmp(optarg, "stderr_syslog")) {
				log_method = L_STDERR_SYSLOG;
			} else if (!strcmp(optarg, "stderr")) {
				log_method = L_STDERR;
			} else if (!strcmp(optarg, "logfile")) {
				log_method = L_LOGFILE;
			} else if (!strcmp(optarg, "none")) {
				log_method = L_NONE;
			} else {
				fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
				exit(1);
			}
			break;
		case 't':
			chrootdir = strdup(optarg);
			break;
		case 'u':
			username = strdup(optarg);
			break;
		case 'v':
			version();
			break;
		case 'c':
			configtest = 1;
			break;
		case 'n':
			daemonize = 0;
			break;
		case 'h':
			usage(pname);
#ifdef HAVE_GETOPT_LONG
		case ':':
			fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name);
			exit(1);
#endif
		case '?':
			exit(1);
		}
	}

	/* TODO: Seems like this chroot'ing should happen *after* daemonizing for
	 * the sake of the PID file. */
	if (chrootdir) {
		if (!username) {
			fprintf(stderr, "Chroot as root is not safe, exiting\n");
			exit(1);
		}

		if (chroot(chrootdir) == -1) {
			perror("chroot");
			exit(1);
		}

		if (chdir("/") == -1) {
			perror("chdir");
			exit(1);
		}
		/* username will be switched later */
	}

	if (configtest) {
		set_debuglevel(1);
		log_method = L_STDERR;
	}

	if (log_open(log_method, pname, logfile, facility) < 0) {
		perror("log_open");
		exit(1);
	}

	if (!configtest) {
		flog(LOG_INFO, "version %s started", VERSION);
	}

	/* check that 'other' cannot write the file
	 * for non-root, also that self/own group can't either
	 */
	if (check_conffile_perm(username, conf_path) != 0) {
		if (get_debuglevel() == 0) {
			flog(LOG_ERR, "exiting, permissions on conf_file invalid");
			exit(1);
		} else
			flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
	}

	/* parse config file */
	struct Interface *ifaces = NULL;
	if ((ifaces = readin_config(conf_path)) == 0) {
		flog(LOG_ERR, "exiting, failed to read config file");
		exit(1);
	}

	if (configtest) {
		free_ifaces(ifaces);
		exit(0);
	}

	/* get a raw socket for sending and receiving ICMPv6 messages */
	int sock = open_icmpv6_socket();
	if (sock < 0) {
		perror("open_icmpv6_socket");
		exit(1);
	}

	/* if we know how to do it, check whether forwarding is enabled */
	if (check_ip6_forwarding()) {
		flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway");
	}

	int const pidfd = open_and_lock_pid_file(daemon_pid_file_ident);

	/*
	 * okay, config file is read in, socket and stuff is setup, so
	 * lets fork now...
	 */
	if (daemonize) {
		pid_t pid = do_daemonize(log_method, daemon_pid_file_ident);
		if (pid != 0 && pid != -1) {
			/* We want to see clean output from valgrind, so free username, chrootdir,
			 * and ifaces in the child process. */
			if (ifaces)
				free_ifaces(ifaces);

			if (username)
				free(username);

			if (chrootdir)
				free(chrootdir);

			exit(0);
		}
	} else {
		if (0 != write_pid_file(daemon_pid_file_ident, getpid())) {
			flog(LOG_ERR, "failure writing pid file detected");
			exit(-1);
		}
	}

	check_pid_file(daemon_pid_file_ident);

#ifdef __linux__
	/* for privsep */ {
		dlog(LOG_DEBUG, 3, "initializing privsep");

		int pipefds[2];

		if (pipe(pipefds) != 0) {
			flog(LOG_ERR, "Couldn't create privsep pipe.");
			return -1;
		}

		pid_t pid = fork();

		if (pid == -1) {
			flog(LOG_ERR, "Couldn't fork for privsep.");
			return -1;
		}

		if (pid == 0) {
			/* We want to see clean output from valgrind, so free username, chrootdir,
			 * and ifaces in the child process. */
			if (ifaces)
				free_ifaces(ifaces);

			if (username)
				free(username);

			if (chrootdir)
				free(chrootdir);

			close(pipefds[1]);

			privsep_init(pipefds[0]);
			_exit(0);
		}

		dlog(LOG_DEBUG, 3, "radvd privsep PID is %d", pid);

		/* Continue execution (will drop privileges soon) */
		close(pipefds[0]);
		privsep_set_write_fd(pipefds[1]);
	}
#endif

	if (username) {
		if (drop_root_privileges(username) < 0) {
			perror("drop_root_privileges");
			flog(LOG_ERR, "unable to drop root privileges");
			exit(1);
		}
		dlog(LOG_DEBUG, 3, "running as user: %s", username);
	}

	setup_ifaces(sock, ifaces);
	ifaces = main_loop(sock, ifaces, conf_path);
	stop_adverts(sock, ifaces);

	flog(LOG_INFO, "removing %s", daemon_pid_file_ident);
	unlink(daemon_pid_file_ident);
	close(pidfd);

	if (ifaces)
		free_ifaces(ifaces);

	if (chrootdir)
		free(chrootdir);

	if (username)
		free(username);

	flog(LOG_INFO, "returning from radvd main");
	log_close();

	return 0;
}