-/* $Log: secnet.c,v $
- * Revision 1.1 1996/03/13 22:27:41 sde1000
- * Initial revision
- *
- */
-
extern char version[];
#include "secnet.h"
#include "util.h"
#include "conffile.h"
+#include "process.h"
-/* Command-line options (possibly config-file options too) */
-static char *configfile="/etc/secnet/secnet.conf";
+/* XXX should be from autoconf */
+static const char *configfile="/etc/secnet/secnet.conf";
+static const char *sites_key="sites";
bool_t just_check_config=False;
static char *userid=NULL;
static uid_t uid=0;
-static bool_t background=True;
+bool_t background=True;
static char *pidfile=NULL;
+bool_t require_root_privileges=False;
+cstring_t require_root_privileges_explanation=NULL;
+
+static pid_t secnet_pid;
+
+/* from log.c */
+extern uint32_t message_level;
+extern bool_t secnet_is_daemon;
+extern struct log_if *system_log;
+
+/* from process.c */
+extern void start_signal_handling(void);
/* Structures dealing with poll() call */
struct poll_interest {
void *state;
uint32_t max_nfds;
uint32_t nfds;
- string_t desc;
+ cstring_t desc;
struct poll_interest *next;
};
static struct poll_interest *reg=NULL;
{"debug", 1, 0, 'd'},
{"config", 1, 0, 'c'},
{"just-check-config", 0, 0, 'j'},
+ {"sites-key", 1, 0, 's'},
{0,0,0,0}
};
- c=getopt_long(argc, argv, "vwdnjc:ft:",
+ c=getopt_long(argc, argv, "vwdnjc:ft:s:",
long_options, &option_index);
if (c==-1)
break;
switch(c) {
case 2:
/* Help */
- fprintf(stderr,
- "Usage: secnet [OPTION]...\n\n"
- " -f, --silent, --quiet suppress error messages\n"
- " -w, --nowarnings suppress warnings\n"
- " -v, --verbose output extra diagnostics\n"
- " -c, --config=filename specify a configuration file\n"
- " -j, --just-check-config stop after reading configfile\n"
- " -n, --nodetach do not run in background\n"
- " -d, --debug=item,... set debug options\n"
- " --help display this help and exit\n"
- " --version output version information and exit\n"
+ printf("Usage: secnet [OPTION]...\n\n"
+ " -f, --silent, --quiet suppress error messages\n"
+ " -w, --nowarnings suppress warnings\n"
+ " -v, --verbose output extra diagnostics\n"
+ " -c, --config=filename specify a configuration file\n"
+ " -j, --just-check-config stop after reading "
+ "configuration file\n"
+ " -s, --sites-key=name configuration key that "
+ "specifies active sites\n"
+ " -n, --nodetach do not run in background\n"
+ " -d, --debug=item,... set debug options\n"
+ " --help display this help and exit\n"
+ " --version output version information "
+ "and exit\n"
);
exit(0);
break;
case 1:
/* Version */
- fprintf(stderr,"%s\n",version);
+ printf("%s\n",version);
exit(0);
break;
case 'v':
- message_level|=M_INFO|M_WARNING|M_ERROR|M_FATAL;
+ message_level|=M_INFO|M_NOTICE|M_WARNING|M_ERR|M_SECURITY|
+ M_FATAL;
break;
- case 'n':
- background=False;
+ case 'w':
+ message_level&=(~M_WARNING);
break;
case 'd':
- message_level|=M_DEBUG_CONFIG|M_DEBUG_PHASE;
+ message_level|=M_DEBUG_CONFIG|M_DEBUG_PHASE|M_DEBUG;
break;
case 'f':
message_level=M_FATAL;
break;
+ case 'n':
+ background=False;
+ break;
+
case 'c':
if (optarg)
configfile=safe_strdup(optarg,"config_filename");
just_check_config=True;
break;
+ case 's':
+ if (optarg)
+ sites_key=safe_strdup(optarg,"sites-key");
+ else
+ fatal("secnet: no sites key specified");
+ break;
+
case '?':
break;
default:
- Message(M_WARNING,"secnet: Unknown getopt code %c\n",c);
+ Message(M_ERR,"secnet: Unknown getopt code %c\n",c);
}
}
if (argc-optind != 0) {
- Message(M_WARNING,"secnet: You gave extra command line parameters, "
+ Message(M_ERR,"secnet: You gave extra command line parameters, "
"which were ignored.\n");
}
}
list_t *l;
item_t *site;
dict_t *system;
- struct log_if *log;
struct passwd *pw;
struct cloc loc;
int i;
l=dict_lookup(config,"system");
if (!l || list_elem(l,0)->type!=t_dict) {
- fatal("configuration does not include a \"system\" dictionary\n");
+ fatal("configuration does not include a \"system\" dictionary");
}
system=list_elem(l,0)->data.dict;
loc=list_elem(l,0)->loc;
/* Arrange systemwide log facility */
l=dict_lookup(system,"log");
if (!l) {
- fatal("configuration does not include a system/log facility\n");
+ fatal("configuration does not include a system/log facility");
}
- log=init_log(l);
- log->log(log->st,LOG_DEBUG,"%s: logging started",version);
+ system_log=init_log(l);
/* Who are we supposed to run as? */
userid=dict_read_string(system,"userid",False,"system",loc);
} while(pw);
endpwent();
if (uid==0) {
- fatal("userid \"%s\" not found\n",userid);
+ fatal("userid \"%s\" not found",userid);
}
}
/* Pidfile name */
pidfile=dict_read_string(system,"pidfile",False,"system",loc);
+ /* Check whether we need root privileges */
+ if (require_root_privileges && uid!=0) {
+ fatal("the configured feature \"%s\" requires "
+ "that secnet retain root privileges while running.",
+ require_root_privileges_explanation);
+ }
+
/* Go along site list, starting sites */
- l=dict_lookup(config,"sites");
+ l=dict_lookup(config,sites_key);
if (!l) {
- fatal("configuration did not define any remote sites\n");
- }
- i=0;
- while ((site=list_elem(l, i++))) {
- struct site_if *s;
- if (site->type!=t_closure) {
- cfgfatal(site->loc,"system","non-closure in site list");
- }
- if (site->data.closure->type!=CL_SITE) {
- cfgfatal(site->loc,"system","non-site closure in site list");
+ Message(M_WARNING,"secnet: configuration key \"%s\" is missing; no "
+ "remote sites are defined\n",sites_key);
+ } else {
+ i=0;
+ while ((site=list_elem(l, i++))) {
+ struct site_if *s;
+ if (site->type!=t_closure) {
+ cfgfatal(site->loc,"system","non-closure in site list");
+ }
+ if (site->data.closure->type!=CL_SITE) {
+ cfgfatal(site->loc,"system","non-site closure in site list");
+ }
+ s=site->data.closure->interface;
+ s->control(s->st,True);
}
- s=site->data.closure->interface;
- s->control(s->st,True);
}
}
void register_for_poll(void *st, beforepoll_fn *before,
- afterpoll_fn *after, uint32_t max_nfds, string_t desc)
+ afterpoll_fn *after, uint32_t max_nfds, cstring_t desc)
{
struct poll_interest *i;
int timeout;
struct pollfd *fds;
- fds=alloca(sizeof(*fds)*total_nfds);
- if (!fds) {
- fatal("run: couldn't alloca\n");
- }
+ fds=safe_malloc(sizeof(*fds)*total_nfds, "run");
+
+ Message(M_NOTICE,"%s [%d]: starting\n",version,secnet_pid);
- while (!finished) {
+ do {
if (gettimeofday(&tv_now, NULL)!=0) {
fatal_perror("main loop: gettimeofday");
}
- now=(tv_now.tv_sec*1000)+(tv_now.tv_usec/1000);
+ now=((uint64_t)tv_now.tv_sec*(uint64_t)1000)+
+ ((uint64_t)tv_now.tv_usec/(uint64_t)1000);
idx=0;
for (i=reg; i; i=i->next) {
i->after(i->state, fds+idx, i->nfds, &tv_now, &now);
if (rv!=0) {
/* XXX we need to handle this properly: increase the
nfds available */
- fatal("run: beforepoll_fn (%s) returns %d\n",i->desc,rv);
+ fatal("run: beforepoll_fn (%s) returns %d",i->desc,rv);
}
if (timeout<-1) {
- fatal("run: beforepoll_fn (%s) set timeout to %d\n",timeout);
+ fatal("run: beforepoll_fn (%s) set timeout to %d",timeout);
}
idx+=nfds;
remain-=nfds;
i->nfds=nfds;
}
do {
+ if (finished) break;
rv=poll(fds, idx, timeout);
if (rv<0) {
if (errno!=EINTR) {
}
}
} while (rv<0);
- }
+ } while (!finished);
+ free(fds);
}
static void droppriv(void)
{
FILE *pf=NULL;
pid_t p;
+ int errfds[2];
add_hook(PHASE_SHUTDOWN,system_phase_hook,NULL);
- /* Background now, if we're supposed to: we may be unable to write the
- pidfile if we don't. */
- if (background) {
- printf("goto background\n");
- /* Open the pidfile before forking - that way the parent can tell
- whether it succeeds */
- if (pidfile) {
- pf=fopen(pidfile,"w");
- if (!pf) {
- fatal_perror("cannot open pidfile \"%s\"",pidfile);
- }
- } else {
- Message(M_WARNING,"secnet: no pidfile configured, but "
- "backgrounding anyway\n");
+ /* Open the pidfile for writing now: we may be unable to do so
+ once we drop privileges. */
+ if (pidfile) {
+ pf=fopen(pidfile,"w");
+ if (!pf) {
+ fatal_perror("cannot open pidfile \"%s\"",pidfile);
}
+ }
+ if (!background && pf) {
+ fprintf(pf,"%d\n",getpid());
+ fclose(pf);
+ }
+
+ /* Now drop privileges */
+ if (uid!=0) {
+ if (setuid(uid)!=0) {
+ fatal_perror("can't set uid to \"%s\"",userid);
+ }
+ }
+ if (background) {
p=fork();
if (p>0) {
if (pf) {
} else if (p==0) {
/* Child process - all done, just carry on */
if (pf) fclose(pf);
- printf("child\n");
+ /* Close stdin and stdout; we don't need them any more.
+ stderr is redirected to the system/log facility */
+ if (pipe(errfds)!=0) {
+ fatal_perror("can't create pipe for stderr");
+ }
+ close(0);
+ close(1);
+ close(2);
+ dup2(errfds[1],0);
+ dup2(errfds[1],1);
+ dup2(errfds[1],2);
+ secnet_is_daemon=True;
+ setsid();
+ log_from_fd(errfds[0],"stderr",system_log);
} else {
/* Error */
fatal_perror("cannot fork");
exit(1);
}
- } else {
- if (pidfile) {
- pf=fopen(pidfile,"w");
- if (!pf) {
- fatal_perror("cannot open pidfile \"%s\"",pidfile);
- }
- fprintf(pf,"%d\n",getpid());
- fclose(pf);
- }
}
+ secnet_pid=getpid();
+}
- /* Drop privilege now, if configured to do so */
- if (uid!=0) {
- if (setuid(uid)!=0) {
- fatal_perror("can't set uid to \"%s\"",userid);
- }
- }
+static signal_notify_fn finish,ignore_hup;
+static void finish(void *st, int signum)
+{
+ finished=True;
+ Message(M_NOTICE,"%s [%d]: received %s\n",version,secnet_pid,(string_t)st);
+}
+static void ignore_hup(void *st, int signum)
+{
+ Message(M_INFO,"%s [%d]: received SIGHUP\n",version,secnet_pid);
+ return;
}
int main(int argc, char **argv)
enter_phase(PHASE_DROPPRIV);
droppriv();
+ start_signal_handling();
+ request_signal_notification(SIGTERM,finish,safe_strdup("SIGTERM","run"));
+ if (!background) request_signal_notification(SIGINT,finish,
+ safe_strdup("SIGINT","run"));
+ request_signal_notification(SIGHUP,ignore_hup,NULL);
enter_phase(PHASE_RUN);
run();
enter_phase(PHASE_SHUTDOWN);
+ Message(M_NOTICE,"%s [%d]: finished\n",version,secnet_pid);
return 0;
}
-