Beispiel #1
0
void
daemonize(const char *argv0)
{
	(void) argv0;

	detach_from_parent();
	jail();
	drop_root_privileges();
}
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[])
{
	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 #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 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;
}