Example #1
0
static int champ_chooser_new_client(struct async *as, struct conf **confs)
{
	int fd=-1;
	socklen_t t;
	struct asfd *newfd=NULL;
	struct sockaddr_un remote;
	struct blist *blist=NULL;

	t=sizeof(remote);
	if((fd=accept(as->asfd->fd, (struct sockaddr *)&remote, &t))<0)
	{
		logp("accept error in %s: %s\n", __func__, strerror(errno));
		goto error;
	}

	if(!(blist=blist_alloc())
	  || !(newfd=setup_asfd(as, "(unknown)", &fd, /*listen*/"")))
		goto error;
	newfd->blist=blist;
	newfd->set_timeout(newfd, get_int(confs[OPT_NETWORK_TIMEOUT]));

	logp("Connected to fd %d\n", newfd->fd);

	return 0;
error:
	close_fd(&fd);
	blist_free(&blist);
	return -1;
}
Example #2
0
File: main.c Project: EmisFR/burp
static struct asfd *setup_parent_child_pipe(struct async *as,
	const char *desc,
	int *fd_to_use, int *fd_to_close, pid_t childpid,
	enum asfd_fdtype fdtype)
{
	struct asfd *newfd;
	close_fd(fd_to_close);
	if(!(newfd=setup_asfd(as, desc, fd_to_use)))
		return NULL;
	newfd->pid=childpid;
	newfd->fdtype=fdtype;
	return newfd;
}
Example #3
0
struct asfd *champ_chooser_connect(struct async *as,
	struct sdirs *sdirs, struct conf **confs)
{
	int champsock=-1;
	char *champname=NULL;
	struct asfd *chfd=NULL;
	const char *cname=NULL;

	// Connect to champ chooser now.
	// This may start up a new champ chooser. On a machine with multiple
	// cores, it may be faster to do now, way before it is actually needed
	// in phase2.
	if((champsock=connect_to_champ_chooser(sdirs, confs))<0)
	{
		logp("could not connect to champ chooser\n");
		goto error;
	}

	if(!(chfd=setup_asfd(as, "champ chooser socket", &champsock, NULL,
		ASFD_STREAM_STANDARD, ASFD_FD_SERVER_TO_CHAMP_CHOOSER, -1,
			confs))) goto error;

	cname=get_string(confs[OPT_CNAME]);
	if(!(champname=prepend_n("cname", cname, strlen(cname), ":")))
			goto error;

	if(chfd->write_str(chfd, CMD_GEN, champname)
	  || chfd->read_expect(chfd, CMD_GEN, "cname ok"))
		goto error;

	free(champname);
	return chfd;
error:
	free(champname);
	as->asfd_remove(as, chfd);
	asfd_free(&chfd);
	close_fd(&champsock);
	return NULL;
}
Example #4
0
File: child.c Project: vshn/burp
int child(struct async *as, int is_status_server,
	int status_wfd, struct conf **confs, struct conf **cconfs)
{
	int ret=-1;
	int srestore=0;
	int timer_ret=0;
	char *incexc=NULL;
	const char *confs_user;
	const char *cconfs_user;
	const char *confs_group;
	const char *cconfs_group;
	const char *s_script_pre;
	const char *s_script_post;

	// If we are not a status server, we are a normal child - set up the
	// parent socket to write status to.
	if(status_wfd>0)
	{
		if(!(wasfd=setup_asfd(as, "child status pipe", &status_wfd)))
			goto end;
		wasfd->attempt_reads=0;
	}

	/* Has to be before the chuser/chgrp stuff to allow clients to switch
	   to different clients when both clients have different user/group
	   settings. */
	if(extra_comms(as, &incexc, &srestore, confs, cconfs))
	{
		log_and_send(as->asfd, "running extra comms failed on server");
		goto end;
	}

	// Needs to happen after extra_comms, in case extra_comms resets them.
	confs_user=get_string(confs[OPT_USER]);
	cconfs_user=get_string(cconfs[OPT_USER]);
	confs_group=get_string(confs[OPT_GROUP]);
	cconfs_group=get_string(cconfs[OPT_GROUP]);

	/* Now that the client conf is loaded, we might want to chuser or
	   chgrp.
	   The main process could have already done this, so we don't want
	   to try doing it again if cconfs has the same values, because it
	   will fail. */
	if( (!confs_user  || (cconfs_user && strcmp(confs_user, cconfs_user)))
	  ||(!confs_group ||(cconfs_group && strcmp(confs_group,cconfs_group))))
	{
		if(chuser_and_or_chgrp(cconfs_user, cconfs_group))
		{
			log_and_send(as->asfd,
				"chuser_and_or_chgrp failed on server");
			goto end;
		}
	}

	if(as->asfd->read(as->asfd)) goto end;

	// If this is a status server, run the status server.
	if(is_status_server)
	{
		ret=status_server(as, cconfs);
		goto end;
	}

	ret=0;

	s_script_pre=get_string(cconfs[OPT_S_SCRIPT_PRE]);
	s_script_post=get_string(cconfs[OPT_S_SCRIPT_POST]);

	// FIX THIS: Make the script components part of a struct, and just
	// pass in the correct struct. Same below.
	if(s_script_pre)
		ret=run_server_script(as->asfd, "pre",
			s_script_pre,
			get_strlist(cconfs[OPT_S_SCRIPT_PRE_ARG]),
			get_int(cconfs[OPT_S_SCRIPT_PRE_NOTIFY]),
			cconfs, ret, timer_ret);

	if(!ret)
		ret=run_action_server(as, incexc, srestore, &timer_ret, cconfs);

	if((!ret || get_int(cconfs[OPT_S_SCRIPT_POST_RUN_ON_FAIL]))
	  && s_script_post)
		ret=run_server_script(as->asfd, "post",
			s_script_post,
			get_strlist(cconfs[OPT_S_SCRIPT_POST_ARG]),
			get_int(cconfs[OPT_S_SCRIPT_POST_NOTIFY]),
			cconfs, ret, timer_ret);

end:
	return ret;
}
Example #5
0
int champ_chooser_server(struct sdirs *sdirs, struct conf **confs,
	int resume)
{
	int s;
	int ret=-1;
	int len;
	struct asfd *asfd=NULL;
	struct sockaddr_un local;
	struct lock *lock=NULL;
	struct async *as=NULL;
	int started=0;
	struct scores *scores=NULL;
	const char *directory=get_string(confs[OPT_DIRECTORY]);

	if(!(lock=lock_alloc_and_init(sdirs->champlock))
	  || build_path_w(sdirs->champlock))
		goto end;
	lock_get(lock);
	switch(lock->status)
	{
		case GET_LOCK_GOT:
			log_fzp_set(sdirs->champlog, confs);
			logp("Got champ lock for dedup_group: %s\n",
				get_string(confs[OPT_DEDUP_GROUP]));
			break;
		case GET_LOCK_NOT_GOT:
		case GET_LOCK_ERROR:
		default:
			//logp("Did not get champ lock\n");
			goto end;
	}

	if((s=socket(AF_UNIX, SOCK_STREAM, 0))<0)
	{
		logp("socket error in %s: %s\n", __func__, strerror(errno));
		goto end;
	}

	memset(&local, 0, sizeof(struct sockaddr_un));
	local.sun_family=AF_UNIX;
	snprintf(local.sun_path, sizeof(local.sun_path),
		"%s", sdirs->champsock);
	len=strlen(local.sun_path)+sizeof(local.sun_family)+1;
	unlink(sdirs->champsock);
	if(bind(s, (struct sockaddr *)&local, len)<0)
	{
		logp("bind error in %s: %s\n", __func__, strerror(errno));
		goto end;
	}

	if(listen(s, 5)<0)
	{
		logp("listen error in %s: %s\n", __func__, strerror(errno));
		goto end;
	}

	if(!(as=async_alloc())
	  || as->init(as, 0)
	  || !(asfd=setup_asfd(as, "champ chooser main socket", &s,
		/*listen*/"")))
			goto end;
	asfd->fdtype=ASFD_FD_SERVER_LISTEN_MAIN;

	// I think that this is probably the best point at which to run a
	// cleanup job to delete unused data files, because no other process
	// can fiddle with the dedup_group at this point.
	// Cannot do it on a resume, or it will delete files that are
	// referenced in the backup we are resuming.
	if(delete_unused_data_files(sdirs, resume))
		goto end;

	// Load the sparse indexes for this dedup group.
	if(!(scores=champ_chooser_init(sdirs->data)))
		goto end;

	while(1)
	{
		for(asfd=as->asfd->next; asfd; asfd=asfd->next)
		{
			if(!asfd->blist->head
			  || asfd->blist->head->got==BLK_INCOMING) continue;
			if(results_to_fd(asfd)) goto end;
		}

		int removed;

		switch(as->read_write(as))
		{
			case 0:
				// Check the main socket last, as it might add
				// a new client to the list.
				for(asfd=as->asfd->next; asfd; asfd=asfd->next)
				{
					while(asfd->rbuf->buf)
					{
						if(deal_with_client_rbuf(asfd,
							directory, scores))
								goto end;
						// Get as much out of the
						// readbuf as possible.
						if(asfd->parse_readbuf(asfd))
							goto end;
					}
				}
				if(as->asfd->new_client)
				{
					// Incoming client.
					as->asfd->new_client=0;
					if(champ_chooser_new_client(as, confs))
						goto end;
					started=1;
				}
				break;
			default:
				removed=0;
				// Maybe one of the fds had a problem.
				// Find and remove it and carry on if possible.
				for(asfd=as->asfd->next; asfd; )
				{
					struct asfd *a;
					if(!asfd->want_to_remove)
					{
						asfd=asfd->next;
						continue;
					}
					as->asfd_remove(as, 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;
		}
				
		if(started && !as->asfd->next)
		{
			logp("All clients disconnected.\n");
			ret=0;
			break;
		}
	}

end:
	logp("champ chooser exiting: %d\n", ret);
	champ_chooser_free(&scores);
	log_fzp_set(NULL, confs);
	async_free(&as);
	asfd_free(&asfd); // This closes s for us.
	close_fd(&s);
	unlink(sdirs->champsock);
// FIX THIS: free asfds.
	lock_release(lock);
	lock_free(&lock);
	return ret;
}
Example #6
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 #7
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 #8
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;
}