mirror of
https://bitbucket.org/jsuto/piler.git
synced 2024-12-26 17:10:12 +01:00
247 lines
4.5 KiB
C
247 lines
4.5 KiB
C
/*
|
|
* piler.c, SJ
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/time.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <signal.h>
|
|
#include <syslog.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <locale.h>
|
|
#include <errno.h>
|
|
#include <piler.h>
|
|
|
|
|
|
extern char *optarg;
|
|
extern int optind;
|
|
|
|
int sd;
|
|
int nconn = 0;
|
|
char *configfile = CONFIG_FILE;
|
|
struct __config cfg;
|
|
struct __data data;
|
|
struct passwd *pwd;
|
|
|
|
|
|
void clean_exit(){
|
|
if(sd != -1) close(sd);
|
|
|
|
syslog(LOG_PRIORITY, "%s has been terminated", PROGNAME);
|
|
|
|
unlink(cfg.pidfile);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
|
|
void fatal(char *s){
|
|
syslog(LOG_PRIORITY, "%s\n", s);
|
|
clean_exit();
|
|
}
|
|
|
|
|
|
void sigchld(){
|
|
int pid, wstat;
|
|
|
|
while((pid = wait_nohang(&wstat)) > 0){
|
|
if(nconn > 0) nconn--;
|
|
}
|
|
}
|
|
|
|
|
|
void initialiseConfiguration(){
|
|
|
|
cfg = read_config(configfile);
|
|
|
|
if(strlen(cfg.username) > 1){
|
|
pwd = getpwnam(cfg.username);
|
|
if(!pwd) fatal(ERR_NON_EXISTENT_USER);
|
|
}
|
|
|
|
|
|
if(getuid() == 0 && pwd){
|
|
check_and_create_directories(&cfg, pwd->pw_uid, pwd->pw_gid);
|
|
}
|
|
|
|
|
|
if(chdir(cfg.workdir)){
|
|
syslog(LOG_PRIORITY, "workdir: *%s*", cfg.workdir);
|
|
fatal(ERR_CHDIR);
|
|
}
|
|
|
|
setlocale(LC_MESSAGES, cfg.locale);
|
|
setlocale(LC_CTYPE, cfg.locale);
|
|
|
|
data.blackhole = NULL;
|
|
|
|
syslog(LOG_PRIORITY, "reloaded config: %s", configfile);
|
|
|
|
#ifdef HAVE_MEMCACHED
|
|
memcached_init(&(data.memc), cfg.memcached_servers, 11211);
|
|
#endif
|
|
}
|
|
|
|
|
|
int read_key(struct __config *cfg){
|
|
int fd, n;
|
|
|
|
fd = open(KEYFILE, O_RDONLY);
|
|
if(fd == -1){
|
|
syslog(LOG_PRIORITY, "cannot read keyfile: %s", KEYFILE);
|
|
return -1;
|
|
}
|
|
|
|
n = read(fd, cfg->key, KEYLEN);
|
|
|
|
close(fd);
|
|
|
|
if(n > 5) return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv){
|
|
int i, new_sd, yes=1, pid, daemonise=0;
|
|
unsigned int clen;
|
|
struct sockaddr_in client_addr, serv_addr;
|
|
struct in_addr addr;
|
|
|
|
while((i = getopt(argc, argv, "c:dvVh")) > 0){
|
|
switch(i){
|
|
|
|
case 'c' :
|
|
configfile = optarg;
|
|
break;
|
|
|
|
case 'd' :
|
|
daemonise = 1;
|
|
break;
|
|
|
|
case 'v' :
|
|
case 'V' :
|
|
__fatal(PROGNAME " " PROGINFO);
|
|
break;
|
|
|
|
case 'h' :
|
|
default :
|
|
__fatal("usage: ...");
|
|
}
|
|
}
|
|
|
|
(void) openlog(PROGNAME, LOG_PID, LOG_MAIL);
|
|
|
|
sig_catch(SIGINT, clean_exit);
|
|
sig_catch(SIGQUIT, clean_exit);
|
|
sig_catch(SIGKILL, clean_exit);
|
|
sig_catch(SIGTERM, clean_exit);
|
|
sig_catch(SIGHUP, initialiseConfiguration);
|
|
|
|
|
|
data.blackhole = NULL;
|
|
|
|
|
|
sig_block(SIGCHLD);
|
|
sig_catch(SIGCHLD, sigchld);
|
|
|
|
|
|
initialiseConfiguration();
|
|
|
|
|
|
if(read_key(&cfg)) fatal(ERR_READING_KEY);
|
|
|
|
|
|
if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
|
fatal(ERR_OPEN_SOCKET);
|
|
|
|
serv_addr.sin_family = AF_INET;
|
|
serv_addr.sin_port = htons(cfg.listen_port);
|
|
inet_aton(cfg.listen_addr, &addr);
|
|
serv_addr.sin_addr.s_addr = addr.s_addr;
|
|
bzero(&(serv_addr.sin_zero), 8);
|
|
|
|
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
|
|
fatal(ERR_SET_SOCK_OPT);
|
|
|
|
if(bind(sd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
|
|
fatal(ERR_BIND_TO_PORT);
|
|
|
|
if(listen(sd, cfg.backlog) == -1)
|
|
fatal(ERR_LISTEN);
|
|
|
|
|
|
if(drop_privileges(pwd)) fatal(ERR_SETUID);
|
|
|
|
|
|
syslog(LOG_PRIORITY, "%s %s starting", PROGNAME, VERSION);
|
|
|
|
|
|
#if HAVE_DAEMON == 1
|
|
if(daemonise == 1) i = daemon(1, 0);
|
|
#endif
|
|
|
|
write_pid_file(cfg.pidfile);
|
|
|
|
|
|
/* main accept loop */
|
|
|
|
for(;;){
|
|
|
|
/* let new connections wait if we are too busy now */
|
|
|
|
if(nconn >= cfg.max_connections) sig_pause();
|
|
|
|
clen = sizeof(client_addr);
|
|
|
|
sig_unblock(SIGCHLD);
|
|
new_sd = accept(sd, (struct sockaddr *)&client_addr, &clen);
|
|
sig_block(SIGCHLD);
|
|
|
|
if(new_sd == -1) continue;
|
|
|
|
pid = fork();
|
|
|
|
if(pid == 0){
|
|
sig_uncatch(SIGCHLD);
|
|
sig_unblock(SIGCHLD);
|
|
|
|
sig_uncatch(SIGINT);
|
|
sig_uncatch(SIGQUIT);
|
|
sig_uncatch(SIGKILL);
|
|
sig_uncatch(SIGTERM);
|
|
sig_block(SIGHUP);
|
|
|
|
syslog(LOG_PRIORITY, "connection from client: %s", inet_ntoa(client_addr.sin_addr));
|
|
|
|
handle_smtp_session(new_sd, &data, &cfg);
|
|
|
|
_exit(0);
|
|
}
|
|
|
|
else if(pid > 0){
|
|
nconn++;
|
|
}
|
|
|
|
else {
|
|
syslog(LOG_PRIORITY, "%s", ERR_FORK_FAILED);
|
|
}
|
|
|
|
close(new_sd);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|