Example #1
0
int status_client_ncurses(struct conf **confs)
{
        int ret=-1;
	int csin=-1;
	int csout=-1;
	pid_t childpid=-1;
	struct async *as=NULL;
	const char *monitor_logfile=get_string(confs[OPT_MONITOR_LOGFILE]);
	struct asfd *so_asfd=NULL;
	struct sel *sel=NULL;

	if(!(sel=sel_alloc()))
		goto end;

	setup_signals();

	// Fork a burp child process that will contact the server over SSL.
	// We will read and write from and to its stdout and stdin.
	if((childpid=fork_monitor(&csin, &csout, confs))<0)
		goto end;
//printf("childpid: %d\n", childpid);

	if(!(as=async_alloc())
	  || as->init(as, 0)
	  || !setup_asfd_linebuf_write(as, "monitor stdin", &csin)
	  || !setup_asfd_linebuf_read(as, "monitor stdout", &csout))
		goto end;
//printf("ml: %s\n", monitor_logfile);
#ifdef HAVE_NCURSES
	if(actg==ACTION_STATUS)
	{
		if(!setup_asfd_ncurses_stdin(as))
			goto end;
		ncurses_init();
	}
#endif
	if(!(so_asfd=setup_asfd_stdout(as)))
		goto end;

	if(monitor_logfile
	  && !(lfzp=fzp_open(monitor_logfile, "wb")))
		goto end;
	log_fzp_set_direct(lfzp);

	ret=status_client_ncurses_main_loop(as, so_asfd, sel,
		get_string(confs[OPT_ORIG_CLIENT]));
end:
#ifdef HAVE_NCURSES
	if(actg==ACTION_STATUS)
		ncurses_free();
#endif
	if(ret) logp("%s exiting with error: %d\n", __func__, ret);
	fzp_close(&lfzp);
	async_asfd_free_all(&as);
	close_fd(&csin);
	close_fd(&csout);
	sel_free(&sel);
	return ret;
}
Example #2
0
File: main.c Project: EmisFR/burp
static int run_server(struct conf **confs, const char *conffile,
	int *rfds, int *sfds)
{
	int i=0;
	int ret=-1;
	SSL_CTX *ctx=NULL;
	int found_normal_child=0;
	struct asfd *asfd=NULL;
	struct asfd *scfd=NULL;
	struct async *mainas=NULL;
	const char *port=get_string(confs[OPT_PORT]);
	const char *address=get_string(confs[OPT_ADDRESS]);
	const char *status_port=get_string(confs[OPT_STATUS_PORT]);
	const char *status_address=get_string(confs[OPT_STATUS_ADDRESS]);

	if(!(ctx=ssl_initialise_ctx(confs)))
	{
		logp("error initialising ssl ctx\n");
		goto end;
	}
	if((ssl_load_dh_params(ctx, confs)))
	{
		logp("error loading dh params\n");
		goto end;
	}

	if(init_listen_socket(address, port, rfds)
	  || init_listen_socket(status_address, status_port, sfds))
		goto end;

	if(!(mainas=async_alloc())
	  || mainas->init(mainas, 0))
		goto end;

	for(i=0; i<LISTEN_SOCKETS && rfds[i]!=-1; i++)
	{
		struct asfd *newfd;
		if(!(newfd=setup_asfd(mainas,
			"main server socket", &rfds[i])))
				goto end;
		newfd->fdtype=ASFD_FD_SERVER_LISTEN_MAIN;
	}
	for(i=0; i<LISTEN_SOCKETS && sfds[i]!=-1; i++)
	{
		struct asfd *newfd;
		if(!(newfd=setup_asfd(mainas,
			"main server status socket", &sfds[i])))
				goto end;
		newfd->fdtype=ASFD_FD_SERVER_LISTEN_STATUS;
	}

	while(!hupreload)
	{
		switch(mainas->read_write(mainas))
		{
			case 0:
				for(asfd=mainas->asfd; asfd; asfd=asfd->next)
				{
					if(asfd->new_client)
					{
						// Incoming client.
						asfd->new_client=0;
						if(process_incoming_client(asfd,
							ctx, conffile, confs))
								goto end;
						if(!get_int(confs[OPT_FORK]))
						{
							gentleshutdown++;
							ret=1;
							goto end;
						}
						continue;
					}
				}
				break;
			default:
				int removed=0;
				// Maybe one of the fds had a problem.
				// Find and remove it and carry on if possible.
				for(asfd=mainas->asfd; asfd; )
				{
					struct asfd *a;
					if(!asfd->want_to_remove)
					{
						asfd=asfd->next;
						continue;
					}
					mainas->asfd_remove(mainas, asfd);
					logp("%s: disconnected fd %d\n",
						asfd->desc, asfd->fd);
					a=asfd->next;
					asfd_free(&asfd);
					asfd=a;
					removed++;
				}
				if(removed) break;
				// If we got here, there was no fd to remove.
				// It is a fatal error.
				goto end;
		}

		for(asfd=mainas->asfd; asfd; asfd=asfd->next)
		{
			if(asfd->fdtype!=ASFD_FD_SERVER_PIPE_READ
			  || !asfd->rbuf->buf) continue;
			// One of the child processes is giving us information.
			// Try to append it to any of the status child pipes.
			for(scfd=mainas->asfd; scfd; scfd=scfd->next)
			{
				if(scfd->fdtype!=ASFD_FD_SERVER_PIPE_WRITE)
					continue;
				switch(scfd->append_all_to_write_buffer(scfd,
					asfd->rbuf))
				{
					case APPEND_OK:
					case APPEND_BLOCKED:
						break;
					default:
						goto end;
				}
			}
			// Free the information, even if we did not manage
			// to append it. That should be OK, more will be along
			// soon.
			iobuf_free_content(asfd->rbuf);
		}

		chld_check_for_exiting(mainas);

		// Leave if we had a SIGUSR1 and there are no children running.
		if(gentleshutdown)
		{
			if(!gentleshutdown_logged)
			{
				logp("got SIGUSR2 gentle reload signal\n");
				logp("will shut down once children have exited\n");
				gentleshutdown_logged++;
			}
// FIX THIS:
// found_normal_child=chld_add_fd_to_normal_sets(confs, &fsr, &fse, &mfd);
			else if(!found_normal_child)
			{
				logp("all children have exited - shutting down\n");
				break;
			}
		}
	}

	if(hupreload) logp("got SIGHUP reload signal\n");

	ret=0;
end:
	async_asfd_free_all(&mainas);
	if(ctx) ssl_destroy_ctx(ctx);
	return ret;
}
Example #3
0
File: main.c Project: EmisFR/burp
static int run_child(int *cfd, SSL_CTX *ctx, struct sockaddr_storage *addr,
	int status_wfd, int status_rfd, const char *conffile, int forking)
{
	int ret=-1;
	int ca_ret=0;
	SSL *ssl=NULL;
	BIO *sbio=NULL;
	struct conf **confs=NULL;
	struct conf **cconfs=NULL;
	struct cntr *cntr=NULL;
	struct async *as=NULL;
	const char *cname=NULL;
	struct asfd *asfd=NULL;
	int is_status_server=0;

	if(!(confs=confs_alloc())
	  || !(cconfs=confs_alloc()))
		goto end;

	set_peer_env_vars(addr);

	// Reload global config, in case things have changed. This means that
	// the server does not need to be restarted for most conf changes.
	confs_init(confs);
	confs_init(cconfs);
	if(conf_load_global_only(conffile, confs)) goto end;

	// Hack to keep forking turned off if it was specified as off on the
	// command line.
	if(!forking) set_int(confs[OPT_FORK], 0);

	if(!(sbio=BIO_new_socket(*cfd, BIO_NOCLOSE))
	  || !(ssl=SSL_new(ctx)))
	{
		logp("There was a problem joining ssl to the socket\n");
		goto end;
	}
	SSL_set_bio(ssl, sbio, sbio);

	/* Do not try to check peer certificate straight away.
	   Clients can send a certificate signing request when they have
	   no certificate. */
	SSL_set_verify(ssl, SSL_VERIFY_PEER
		/* | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */, 0);

	if(ssl_do_accept(ssl))
		goto end;
	if(!(as=async_alloc())
	  || as->init(as, 0)
	  || !(asfd=setup_asfd_ssl(as, "main socket", cfd, ssl)))
		goto end;
	asfd->set_timeout(asfd, get_int(confs[OPT_NETWORK_TIMEOUT]));
	asfd->ratelimit=get_float(confs[OPT_RATELIMIT]);

	if(authorise_server(as->asfd, confs, cconfs)
	  || !(cname=get_string(cconfs[OPT_CNAME])) || !*cname)
	{
		// Add an annoying delay in case they are tempted to
		// try repeatedly.
		log_and_send(as->asfd, "unable to authorise on server");
		sleep(1);
		goto end;
	}

	if(!get_int(cconfs[OPT_ENABLED]))
	{
		log_and_send(as->asfd, "client not enabled on server");
		sleep(1);
		goto end;
	}

	// Set up counters. Have to wait until here to get cname.
	if(!(cntr=cntr_alloc())
	  || cntr_init(cntr, cname))
		goto end;
	set_cntr(confs[OPT_CNTR], cntr);
	set_cntr(cconfs[OPT_CNTR], cntr);

	/* At this point, the client might want to get a new certificate
	   signed. Clients on 1.3.2 or newer can do this. */
	if((ca_ret=ca_server_maybe_sign_client_cert(as->asfd, confs, cconfs))<0)
	{
		logp("Error signing client certificate request for %s\n",
			cname);
		goto end;
	}
	else if(ca_ret>0)
	{
		// Certificate signed and sent back.
		// Everything is OK, but we will close this instance
		// so that the client can start again with a new
		// connection and its new certificates.
		logp("Signed and returned client certificate request for %s\n",
			cname);
		ret=0;
		goto end;
	}

	/* Now it is time to check the certificate. */
	if(ssl_check_cert(ssl, confs, cconfs))
	{
		log_and_send(as->asfd, "check cert failed on server");
		goto end;
	}

	if(status_rfd>=0)
	{
		is_status_server=1;
		if(!setup_asfd(as, "status server parent socket", &status_rfd))
			goto end;
	}

	ret=child(as, is_status_server, status_wfd, confs, cconfs);
end:
	*cfd=-1;
	if(as && asfd_flush_asio(as->asfd))
		ret=-1;
	async_asfd_free_all(&as); // This closes cfd for us.
	logp("exit child\n");
	if(cntr) cntr_free(&cntr);
	if(confs)
	{
		set_cntr(confs[OPT_CNTR], NULL);
		confs_free(&confs);
	}
	if(cconfs)
	{
		set_cntr(cconfs[OPT_CNTR], NULL);
		confs_free(&cconfs);
	}
	return ret;
}
Example #4
0
File: main.c Project: EmisFR/burp
static int process_incoming_client(struct asfd *asfd, SSL_CTX *ctx,
	const char *conffile, struct conf **confs)
{
	int cfd=-1;
	pid_t childpid;
	int pipe_rfd[2];
	int pipe_wfd[2];
	socklen_t client_length=0;
	struct sockaddr_storage client_name;
	enum asfd_fdtype fdtype=asfd->fdtype;
	int forking=get_int(confs[OPT_FORK]);

	client_length=sizeof(client_name);
	if((cfd=accept(asfd->fd,
		(struct sockaddr *)&client_name, &client_length))==-1)
	{
		// Look out, accept will get interrupted by SIGCHLDs.
		if(errno==EINTR) return 0;
		logp("accept failed on %s (%d) in %s: %s\n", asfd->desc,
			asfd->fd, __func__, strerror(errno));
		return -1;
	}
	reuseaddr(cfd);
	if(log_peer_address(&client_name))
		return -1;

	if(!forking)
		return run_child(&cfd, ctx,
			&client_name, -1, -1, conffile, forking);

	if(chld_check_counts(confs, asfd))
	{
		logp("Closing new connection.\n");
		close_fd(&cfd);
		return 0;
	}

	if(pipe(pipe_rfd)<0 || pipe(pipe_wfd)<0)
	{
		logp("pipe failed: %s", strerror(errno));
		close_fd(&cfd);
		return -1;
	}

	switch((childpid=fork()))
	{
		case -1:
			logp("fork failed: %s\n", strerror(errno));
			return -1;
		case 0:
		{
			// Child.
			int p;
			int ret;
			struct sigaction sa;
			struct async *as=asfd->as;
			async_asfd_free_all(&as);

			// Close unnecessary file descriptors.
			// Go up to FD_SETSIZE and hope for the best.
			// FIX THIS: Now that async_asfd_free_all() is doing
			// everything, double check whether this is needed.
			for(p=3; p<(int)FD_SETSIZE; p++)
			{
				if(p!=pipe_rfd[1]
				  && p!=pipe_wfd[0]
				  && p!=cfd)
					close(p);
			}

			// Set SIGCHLD back to default, so that I
			// can get sensible returns from waitpid.
			memset(&sa, 0, sizeof(sa));
			sa.sa_handler=SIG_DFL;
			sigaction(SIGCHLD, &sa, NULL);

			close(pipe_rfd[0]); // close read end
			close(pipe_wfd[1]); // close write end

			confs_free_content(confs);
			confs_init(confs);

			ret=run_child(&cfd, ctx, &client_name, pipe_rfd[1],
			  fdtype==ASFD_FD_SERVER_LISTEN_STATUS?pipe_wfd[0]:-1,
			  conffile, forking);

			close(pipe_rfd[1]);
			close(pipe_wfd[0]);
			close_fd(&cfd);
			exit(ret);
		}
		default:
			// Parent.
			close(pipe_rfd[1]); // close write end
			close(pipe_wfd[0]); // close read end
			close_fd(&cfd);

			return setup_parent_child_pipes(asfd, childpid,
				&pipe_rfd[0], &pipe_wfd[1]);
	}
}
Example #5
0
int status_client_ncurses(enum action act, struct conf **confs)
{
	int csin=-1;
	int csout=-1;
        int ret=-1;
	pid_t childpid=-1;
	struct async *as=NULL;
	const char *monitor_logfile=get_string(confs[OPT_MONITOR_LOGFILE]);

#ifdef HAVE_NCURSES_H
	actg=act; // So that the sighandler can call endwin().
#else
	if(act==ACTION_STATUS)
	{
		printf("To use the live status monitor, you need to recompile with ncurses support.\n");
		goto end;
	}
#endif

	setup_signals();

	// Fork a burp child process that will contact the server over SSL.
	// We will read and write from and to its stdout and stdin.
	if((childpid=fork_monitor(&csin, &csout, confs))<0)
		goto end;
//printf("childpid: %d\n", childpid);
	set_non_blocking(csin);
	set_non_blocking(csout);

	if(!(as=async_alloc())
	  || as->init(as, 0)
	  || !setup_asfd(as, "monitor stdin", &csin, NULL,
		ASFD_STREAM_LINEBUF, ASFD_FD_CLIENT_MONITOR_WRITE, -1, confs)
	  || !setup_asfd(as, "monitor stdout", &csout, NULL,
		ASFD_STREAM_LINEBUF, ASFD_FD_CLIENT_MONITOR_READ, -1, confs))
			goto end;
//printf("ml: %s\n", monitor_logfile);
#ifdef HAVE_NCURSES_H
	if(actg==ACTION_STATUS)
	{
		int stdinfd=fileno(stdin);
		if(!setup_asfd(as, "stdin", &stdinfd, NULL,
			ASFD_STREAM_NCURSES_STDIN, ASFD_FD_CLIENT_NCURSES_READ,
			-1, confs))
				goto end;
		ncurses_init();
	}
#endif
	if(monitor_logfile
	  && !(lfp=open_file(monitor_logfile, "wb")))
		goto end;
	set_logfp_direct(lfp);

	ret=main_loop(as, act, confs);
end:
#ifdef HAVE_NCURSES_H
	if(actg==ACTION_STATUS) endwin();
#endif
	if(ret) logp("%s exiting with error: %d\n", __func__, ret);
	close_fp(&lfp);
	async_asfd_free_all(&as);
	close_fd(&csin);
	close_fd(&csout);
	return ret;
}