diff options
Diffstat (limited to 'src/sslhandle.c')
-rw-r--r-- | src/sslhandle.c | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/src/sslhandle.c b/src/sslhandle.c new file mode 100644 index 0000000..f31cee9 --- /dev/null +++ b/src/sslhandle.c @@ -0,0 +1,887 @@ +/** + @file sslhandle.c + @author web, feh + @brief IPv6 enabled TLS framework for a preforking server +*/ +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <netdb.h> +#include <signal.h> +#include <arpa/inet.h> +#include "ucspissl.h" +#include "uint_t.h" +#include "str.h" +#include "byte.h" +#include "fmt.h" +#include "scan.h" +#include "ip.h" +#include "fd.h" +#include "exit.h" +#include "env.h" +#include "prot.h" +#include "open.h" +#include "wait.h" +#include "stralloc.h" +#include "alloc.h" +#include "buffer.h" +#include "getln.h" +#include "logmsg.h" +#include "getoptb.h" +#include "socket_if.h" +#include "ndelay.h" +#include "remoteinfo.h" +#include "rules.h" +#include "sig.h" +#include "iopause.h" +#include "dnsresolv.h" +#include "auto_cafile.h" +#include "auto_cadir.h" +#include "auto_ccafile.h" +#include "auto_dhfile.h" +#include "auto_certchainfile.h" +#include "auto_certfile.h" +#include "auto_keyfile.h" +#include "auto_ciphers.h" +#include "iopause.h" +#include "coe.h" +#include "lock.h" + + +extern void server(int argcs,char * const *argvs); +char *who; + +int verbosity = 1; +int flagkillopts = 1; +int flagafter = 0; +int flagdelay = 0; +const char *banner = ""; +int flagremoteinfo = 1; +int flagremotehost = 1; +int flagparanoid = 0; +int flagclientcert = 0; +int flagsslenv = 0; +int flagtcpenv = 0; +unsigned long timeout = 26; +unsigned long ssltimeout = 26; +unsigned int progtimeout = 3600; +uint32 netif = 0; +int selfpipe[2]; +int flagexit = 0; +int flagdualstack = 0; + +static stralloc tcpremoteinfo = {0}; + +uint16 localport; +char localportstr[FMT_ULONG]; +char localip[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; +char localipstr[IP6_FMT]; +static stralloc localhostsa; +const char *localhost = 0; +const char *lockfile = 0; +int fdlock; + +uint16 remoteport; +char remoteportstr[FMT_ULONG]; +char remoteip[16]; +char remoteipstr[IP6_FMT]; +static stralloc remotehostsa; +char *remotehost = 0; + +const char *hostname; +const char *loopback = "127.0.0.1"; + +static char strnum[FMT_ULONG]; +static char strnum2[FMT_ULONG]; + +static stralloc tmp; +static stralloc fqdn; +static stralloc addresses; +static stralloc certname; +stralloc envplus = {0}; +stralloc envtmp = {0}; + +char bspace[16]; +buffer b; + +SSL_CTX *ctx; +const char *certchainfile = auto_certchainfile; +const char *certfile = auto_certfile; +const char *keyfile = auto_keyfile; +stralloc password = {0}; +int match = 0; +const char *cafile = auto_cafile; +const char *ccafile = auto_ccafile; +const char *cadir = auto_cadir; +const char *ciphers = auto_ciphers; +int verifydepth = 1; +const char *dhfile = auto_dhfile; +int rsalen = SSL_RSA_LEN; + +int pi[2]; +int po[2]; + +X509 *cert; +char buf[SSL_NAME_LEN]; + +char **e; +char **e1; + +/* ---------------------------- child */ + + +int flagdeny = 0; +int flagallownorules = 0; +const char *fnrules = 0; + +void drop_nomem(void) { + logmsg(who,111,FATAL,"out of memory"); +} +void drop_notemp(void) { + logmsg(who,111,FATAL,"out of timestamps"); +} +void cats(const char *s) { + if (!stralloc_cats(&tmp,s)) drop_nomem(); +} +void append(const char *ch) { + if (!stralloc_append(&tmp,ch)) drop_nomem(); +} +void safecats(const char *s) { + char ch; + int i; + + for (i = 0;i < 100;++i) { + ch = s[i]; + if (!ch) return; + if (ch < 33) ch = '?'; + if (ch > 126) ch = '?'; + if (ch == '%') ch = '?'; /* logger stupidity */ + append(&ch); + } + cats("..."); +} +void env(const char *s,const char *t) { + if (!s) return; + if (!stralloc_copys(&envtmp,s)) drop_nomem(); + if (t) { + if (!stralloc_cats(&envtmp,"=")) drop_nomem(); + if (!stralloc_cats(&envtmp,t)) drop_nomem(); + } + if (!stralloc_0(&envtmp)) drop_nomem(); + if (!stralloc_cat(&envplus,&envtmp)) drop_nomem(); +} +static void env_def() { + unsigned int elen; + unsigned int i; + unsigned int j; + unsigned int split; + unsigned int t; + + if (!stralloc_cats(&envplus,"")) return; + + elen = 0; + for (i = 0; environ[i]; ++i) + ++elen; + for (i = 0; i < envplus.len; ++i) + if (!envplus.s[i]) + ++elen; + + e = (char **) alloc((elen + 1) * sizeof(char *)); + if (!e) return; + + elen = 0; + for (i = 0; environ[i]; ++i) + e[elen++] = environ[i]; + + j = 0; + for (i = 0; i < envplus.len; ++i) + if (!envplus.s[i]) { + split = str_chr(envplus.s + j,'='); + for (t = 0;t < elen;++t) + if (byte_equal(envplus.s + j,split,e[t])) + if (e[t][split] == '=') { + --elen; + e[t] = e[elen]; + break; + } + if (envplus.s[j + split]) + e[elen++] = envplus.s + j; + j = i + 1; + } + e[elen] = 0; + + e1 = environ; + environ = e; +} +void env_reset(void) { + if (e) { + if (e != environ) { + alloc_free((char *)e); + logmsg(who,111,FATAL,"environ changed"); + } + } + + environ = e1; + envplus.len = 0; +} +int error_warn(const char *x) { + if (!x) return 0; + log_who(who,"x"); + return 0; +} +void drop_rules(void) { + logmsg(who,111,FATAL,B("unable to read: ",(char *)fnrules)); +} + +void found(char *data,unsigned int datalen) { + unsigned int next0; + unsigned int split; + + while ((next0 = byte_chr(data,datalen,0)) < datalen) { + switch(data[0]) { + case 'D': + flagdeny = 1; + break; + case '+': + split = str_chr(data + 1,'='); + if (data[1 + split] == '=') { + data[1 + split] = 0; + env(data + 1,data + 1 + split + 1); + } + break; + } + ++next0; + data += next0; datalen -= next0; + } +} + +int doit(int t) { + int j; + SSL *ssl; + uint32 netif; + + if (ip6_isv4mapped(remoteip)) { + remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; + localipstr[ip4_fmt(localipstr,localip + 12)] = 0; + } else { + remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; + localipstr[ip6_fmt(localipstr,localip)] = 0; + } + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + log_who(who,B("pid ",strnum," from ",remoteipstr)); + } + + if (socket_local(t,localip,&localport,&netif) == -1) + logmsg(who,111,FATAL,"unable to get local address"); + + remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; + + if (!localhost) + if (dns_name(&localhostsa,localip) >= 0) + if (localhostsa.len) { + if (!stralloc_0(&localhostsa)) drop_nomem(); + localhost = localhostsa.s; + } + + env("PROTO","TLS"); + env("SSLLOCALIP",localipstr); + env("SSLLOCALPORT",localportstr); + env("SSLLOCALHOST",localhost); + env("SSLREMOTEIP",remoteipstr); + env("SSLREMOTEPORT",remoteportstr); + env("SSLREMOTEHOST",remotehost); + + if (flagtcpenv) { + env("TCPLOCALIP",localipstr); + env("TCPLOCALPORT",localportstr); + env("TCPLOCALHOST",localhost); + env("TCPREMOTEIP",remoteipstr); + env("TCPREMOTEPORT",remoteportstr); + env("TCPREMOTEHOST",remotehost); + if (!ip6_isv4mapped(localip)) { + env("PROTO","TCP6"); + env("TCP6LOCALIP",localipstr); + env("TCP6LOCALHOST",localhost); + env("TCP6LOCALPORT",localportstr); + env("TCP6REMOTEIP",remoteipstr); + env("TCP6REMOTEPORT",remoteportstr); + env("TCP6REMOTEHOST",remotehost); + if (netif) + env("TCP6INTERFACE",socket_getifname(netif)); + } else + env("PROTO","TCP"); + } + + if (flagremotehost) + if (dns_name(&remotehostsa,remoteip) >= 0) + if (remotehostsa.len) { + if (flagparanoid) { + if (dns_ip6(&tmp,&remotehostsa) >= 0) + for (j = 0; j + 16 <= tmp.len; j += 16) + if (byte_equal(remoteip,16,tmp.s + j)) { + flagparanoid = 0; + break; + } + if (dns_ip4(&tmp,&remotehostsa) >= 0) + for (j = 0; j + 4 <= tmp.len; j += 4) + if (byte_equal(remoteip,4,tmp.s + j)) { + flagparanoid = 0; + break; + } + } + if (!flagparanoid) { + if (!stralloc_0(&remotehostsa)) drop_nomem(); + remotehost = remotehostsa.s; + } + } + + if (flagremoteinfo) { + if (remoteinfo(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) + flagremoteinfo = 0; + if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); + } + env("SSLREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); + if (flagtcpenv) + env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); + + if (fnrules) { + int fdrules; + flagdeny = 0; + fdrules = open_read(fnrules); + if (fdrules == -1) { + if (errno != ENOENT) drop_rules(); + if (!flagallownorules) drop_rules(); + } else { + if (rules(found,fdrules,remoteipstr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) + drop_rules(); + close(fdrules); + } + } + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + if (!stralloc_copys(&tmp,who)) drop_nomem(); + if (!stralloc_cats(&tmp,": ")) drop_nomem(); + safecats(flagdeny ? "deny" : "ok"); + cats(" "); safecats(strnum); + cats(" "); if (localhost) safecats(localhost); + cats(":"); safecats(localipstr); + cats(":"); safecats(localportstr); + cats(" "); if (remotehost) safecats(remotehost); + cats(":"); safecats(remoteipstr); + cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); + cats(":"); safecats(remoteportstr); + cats("\n"); + buffer_putflush(buffer_2,tmp.s,tmp.len); + } + + if (flagdeny) { + close(t); + return(0); + } + + if (pipe(pi) == -1) logmsg(who,111,FATAL,"unable to create pipe"); + if (pipe(po) == -1) logmsg(who,111,FATAL,"unable to create pipe"); + + ssl = ssl_new(ctx,t); + if (!ssl) logmsg(who,111,FATAL,"unable to create SSL instance"); + if (ndelay_on(t) == -1) + logmsg(who,111,FATAL,"unable to set socket options"); + if (ssl_timeoutaccept(ssl,ssltimeout) == -1) { + strnum[fmt_ulong(strnum,getpid())] = 0; + logmsg(who,110,DROP,B("unable to TLS accept for pid:",strnum)); + ssl_error(error_warn); + } + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + log_who(who,B("tls ",strnum," accept ")); + } + + if (flagclientcert) { + switch(ssl_verify(ssl,remotehost,&certname)) { + case -1: + logmsg(who,110,ERROR,"no client certificate"); + case -2: + logmsg(who,110,ERROR,"missing credentials (CA) or unable to validate client certificate"); + case -3: + if (!stralloc_0(&certname)) drop_nomem(); + logmsg(who,110,ERROR,B("client hostname name does not match certificate: ",remotehost," <=> ",certname.s)); + default: + break; + } + } + + switch(fork()) { + case -1: + logmsg(who,111,FATAL,"unable to fork "); + case 0: + close(pi[0]); close(po[1]); + sig_uncatch(sig_child); + sig_unblock(sig_child); + if (ssl_io(ssl,pi[1],po[0],progtimeout) == -1) { + strnum[fmt_ulong(strnum,getpid())] = 0; + logmsg(who,-99,WARN,B("unable to speak TLS for pid: ",strnum)); + ssl_error(error_warn); + _exit(111); + } + _exit(0); + } + close(pi[1]); close(po[0]); + + if (flagsslenv && !ssl_server_env(ssl,&envplus)) drop_nomem(); + env_def(); + + if (fd_move(0,pi[0]) == -1) + logmsg(who,111,FATAL,"unable to set up descriptor 0"); + if (fd_move(1,po[1]) == -1) + logmsg(who,111,FATAL,"unable to set up descriptor 1"); + + if (flagkillopts) { + socket_ipoptionskill(t); + } + if (!flagdelay) + socket_tcpnodelay(t); + + if (*banner) { + buffer_init(&b,buffer_unixwrite,1,bspace,sizeof(bspace)); + if (buffer_putsflush(&b,banner) == -1) + logmsg(who,111,FATAL,"unable to print banner"); + } + + ssl_free(ssl); + return 1; +} + +void done(void) { + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + if (!stralloc_copys(&tmp,who)) drop_nomem(); + if (!stralloc_cats(&tmp,": ")) drop_nomem(); + cats("done "); safecats(strnum); cats("\n"); + buffer_putflush(buffer_2,tmp.s,tmp.len); + } +} + + +/* ---------------------------- parent */ + +void usage(void) +{ + logmsg(who,100,USAGE,B(who,"\ +[ -1346UXpPhHrRoOdDqQviIeEsS ] \ +[ -c limit ] \ +[ -x rules.cdb ] \ +[ -B banner ] \ +[ -g gid ] \ +[ -u uid ] \ +[ -b backlog ] \ +[ -l localname ] \ +[ -t timeout ] \ +[ -T ssltimeout ] \ +[ -w progtimeout ] \ +[ -f lockfile ] \ +[ -I interface ] \ +host port program")); +} + +unsigned long limit = 40; +unsigned long numchildren = 0; + +int flag1 = 0; +int flag3 = 0; +unsigned long backlog = 20; +unsigned long uid = 0; +unsigned long gid = 0; + +void printstatus(void) { + if (verbosity < 2) return; + strnum[fmt_ulong(strnum,numchildren)] = 0; + strnum2[fmt_ulong(strnum2,limit)] = 0; + log_who(who,B("status: ",strnum,"/",strnum2)); +} + +void trigger(void) { + buffer_unixwrite(selfpipe[1],"",1); +} + +void sigterm(void) { + int pid; + + flagexit = 1; + pid = getpid(); + if (pid < 0) logmsg(who,111,FATAL,"cannot get pid"); + kill(-pid,SIGTERM); + trigger(); +} + +void sigchld(void) { + int wstat; + int pid; + + while ((pid = wait_nohang(&wstat)) > 0) { + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,pid)] = 0; + strnum2[fmt_ulong(strnum2,wstat)] = 0; + log_who(who,B("end ",strnum," status ",strnum2)); + } + if (numchildren) --numchildren; printstatus(); + if (flagexit && !numchildren) _exit(0); + } + trigger(); +} + +void read_passwd(void) { + if (!password.len) { + buffer_init(&b,buffer_unixread,3,bspace,sizeof(bspace)); + if (getln(&b,&password,&match,'\0') == -1) + logmsg(who,111,ERROR,"unable to read password"); + close(3); + if (match) --password.len; + } +} + +int passwd_cb(char *buff,int size,int rwflag,void *userdata) { + if (size < password.len) + logmsg(who,111,ERROR,"password too long"); + + byte_copy(buff,password.len,password.s); + return password.len; +} + +void spawn(int s,int argc,char * const *argv) { + int t; + + while (numchildren >= limit) sig_pause(); + while (numchildren < limit) { + ++numchildren; printstatus(); + + switch(fork()) { + case 0: + sig_uncatch(sig_child); + sig_unblock(sig_child); + sig_uncatch(sig_term); + sig_uncatch(sig_pipe); + for (;;) { + if (lockfile) { + if (lock_ex(fdlock) == -1) + logmsg(who,111,FATAL,B("unable to lock: ",(char *)lockfile)); + if (flagdualstack) + t = socket_accept6(s,remoteip,&remoteport,&netif); + else + t = socket_accept4(s,remoteip,&remoteport); + lock_un(fdlock); + } else { + if (flagdualstack) + t = socket_accept6(s,remoteip,&remoteport,&netif); + else + t = socket_accept4(s,remoteip,&remoteport); + } + + if (t == -1) continue; + if (!doit(t)) continue; + server(argc,argv); + close(0); close(1); + env_reset(); + done(); + } + break; + case -1: + logmsg(who,111,FATAL,"unable to fork"); + --numchildren; printstatus(); + } + } +} + +int main(int argc,char * const *argv) { + int opt; + struct servent *se; + char *x; + int j; + int s; + int ipflag = 0; + iopause_fd io[2]; + char ch; + struct taia deadline; + struct taia stamp; + unsigned long u; + + who = argv[0]; + while ((opt = getopt(argc,argv,"dDvqQhHrRUXx:t:T:u:g:l:b:B:c:pPoO1346I:EeSsaAf:w:zZ")) != opteof) + switch(opt) { + case 'b': scan_ulong(optarg,&backlog); break; + case 'c': scan_ulong(optarg,&limit); break; + case 'X': flagallownorules = 1; break; + case 'x': fnrules = optarg; break; + case 'B': banner = optarg; break; + case 'd': flagdelay = 1; break; + case 'D': flagdelay = 0; break; + case 'v': verbosity = 2; break; + case 'q': verbosity = 0; break; + case 'Q': verbosity = 1; break; + case 'P': flagparanoid = 0; break; + case 'p': flagparanoid = 1; break; + case 'O': flagkillopts = 1; break; + case 'o': flagkillopts = 0; break; + case 'H': flagremotehost = 0; break; + case 'h': flagremotehost = 1; break; + case 'R': flagremoteinfo = 0; break; + case 'r': flagremoteinfo = 1; break; + case 't': scan_ulong(optarg,&timeout); break; + case 'T': scan_ulong(optarg,&ssltimeout); break; + case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid); + x = env_get("GID"); if (x) scan_ulong(x,&gid); break; + case 'u': scan_ulong(optarg,&uid); break; + case 'g': scan_ulong(optarg,&gid); break; + case 'l': localhost = optarg; break; + case 'I': netif = socket_getifidx(optarg); break; + case '1': flag1 = 1; break; + case '3': flag3 = 1; break; + case '4': ipflag = 1; break; + case '6': ipflag = 2; break; + case 'Z': flagclientcert = 0; break; + case 'z': flagclientcert = 1; break; + case 'S': flagsslenv = 0; break; + case 's': flagsslenv = 1; break; + case 'E': flagtcpenv = 0; break; + case 'e': flagtcpenv = 1; break; + case 'A': flagafter = 0; break; + case 'a': flagafter = 1; break; + case 'f': lockfile = optarg; break; + case 'w': scan_uint(optarg,&progtimeout); break; + default: usage(); + } + argc -= optind; + argv += optind; + + if (!verbosity) buffer_2->fd = -1; + + hostname = *argv++; + if (!hostname || str_equal((char *)hostname,"")) usage(); + if (str_equal((char *)hostname,"0")) hostname = loopback; + else if (str_equal((char *)hostname,":0")) { + flagdualstack = 1; + hostname = "::"; + } + + x = *argv++; --argc; + if (!x) usage(); + if (!x[scan_ulong(x,&u)]) + localport = u; + else { + se = getservbyname(x,"tcp"); + if (!se) + logmsg(who,111,FATAL,B("unable to figure out port number for: ",x)); + uint16_unpack_big((char*)&se->s_port,&localport); + } + + if ((x = env_get("VERIFYDEPTH"))) { + scan_ulong(x,&u); + verifydepth = u; + } + + if ((x = env_get("CAFILE"))) cafile = x; + if (cafile && str_equal((char *)cafile,"")) cafile = 0; + + if ((x = env_get("CCAFILE"))) ccafile = x; + if (ccafile && str_equal((char *)ccafile,"")) ccafile = 0; + if (!flagclientcert) ccafile = 0; + + if ((x = env_get("CADIR"))) cadir = x; + if (cadir && str_equal((char *)cadir,"")) cadir= 0; + + if ((x = env_get("CERTCHAINFILE"))) certchainfile = x; + if (certchainfile && str_equal((char *)certchainfile,"")) certchainfile = 0; + + if ((x = env_get("CERTFILE"))) certfile = x; + if (certfile && str_equal((char *)certfile,"")) certfile = 0; + + if ((x = env_get("KEYFILE"))) keyfile = x; + if (keyfile && str_equal((char *)keyfile,"")) keyfile = 0; + + if ((x = env_get("DHFILE"))) dhfile = x; + if (dhfile && str_equal((char *)dhfile,"")) dhfile = 0; + + if ((x = env_get("CIPHERS"))) ciphers = x; + if (ciphers && str_equal((char *)ciphers,"")) ciphers = 0; + + if (setsid() == -1) + if (getpgrp() != getpid()) + logmsg(who,111,FATAL,"unable to create process group"); + + if (lockfile) { + fdlock = open_append(lockfile); + if (fdlock == -1) + logmsg(who,111,FATAL,B("unable to open: ",(char *)lockfile)); + } + + if (pipe(selfpipe) == -1) + logmsg(who,111,FATAL,"unable to create pipe"); + + coe(selfpipe[0]); + coe(selfpipe[1]); + ndelay_on(selfpipe[0]); + ndelay_on(selfpipe[1]); + + sig_block(sig_child); + sig_catch(sig_child,sigchld); + sig_catch(sig_term,sigterm); + sig_ignore(sig_pipe); + + /* IP address only */ + + if (ip4_scan(hostname,localip)) { + if (!stralloc_copyb(&addresses,(char *)V4mappedprefix,12)) drop_nomem(); + if (!stralloc_catb(&addresses,localip,4)) drop_nomem(); + byte_copy(localip,16,addresses.s); + } else if (ip6_scan(hostname,localip)) { + if (!stralloc_copyb(&addresses,localip,16)) drop_nomem(); + byte_copy(localip,16,addresses.s); + } + + /* Asynchronous DNS IPv4/IPv6 Name qualification */ + + if (!addresses.len) { + if (!stralloc_copys(&tmp,hostname)) drop_nomem(); + if (dns_ip_qualify(&addresses,&fqdn,&tmp) < 0) + logmsg(who,111,FATAL,B("temporarily unable to figure out IP address for: ",(char *)hostname)); + + byte_copy(localip,16,addresses.s); + + for (j = 0; j < addresses.len; j += 16) { // Select best matching IP address + if (ipflag == 1 && !ip6_isv4mapped(addresses.s + j)) continue; + if (ipflag == 2 && !ip6_isv4mapped(addresses.s + j)) continue; + byte_copy(localip,16,addresses.s + j); + } + + } + if (addresses.len < 16) + logmsg(who,111,FATAL,B("no IP address for: ",(char *)hostname)); + + if (ip6_isv4mapped(localip)) + s = socket_tcp4(); + else + s = socket_tcp6(); + if (s == -1) + logmsg(who,111,FATAL,"unable to create socket"); + + if (flagdualstack) + socket_dualstack(s); + if (socket_bind_reuse(s,localip,localport,netif) == -1) + logmsg(who,111,FATAL,"unable to bind"); + if (socket_local(s,localip,&localport,&netif) == -1) + logmsg(who,111,FATAL,"unable to get local address"); + if (socket_listen(s,backlog) == -1) + logmsg(who,111,FATAL,"unable to listen"); + ndelay_off(s); + + if (!flagafter) { + if (gid) if (prot_gid(gid) == -1) + logmsg(who,111,FATAL,"unable to set gid"); + if (uid) if (prot_uid(uid) == -1) + logmsg(who,111,FATAL,"unable to set uid"); + } + + if (ip6_isv4mapped(localip)) + localipstr[ip4_fmt(localipstr,localip + 12)] = 0; + else + localipstr[ip6_fmt(localipstr,localip)] = 0; + + localportstr[fmt_ulong(localportstr,localport)] = 0; + + if (flag1) { + buffer_init(&b,buffer_unixwrite,1,bspace,sizeof(bspace)); + buffer_puts(&b,localipstr); + buffer_puts(&b," : "); + buffer_puts(&b,localportstr); + buffer_puts(&b,"\n"); + buffer_flush(&b); + } + + if (flag3) read_passwd(); + + ctx = ssl_server(); + ssl_errstr(); + if (!ctx) logmsg(who,111,FATAL,"unable to create TLS context"); + + if (certchainfile) { + switch (ssl_chainfile(ctx,certchainfile,keyfile,passwd_cb)) { + case -1: logmsg(who,111,ERROR,"unable to load certificate chain file"); + case -2: logmsg(who,111,ERROR,"unable to load key"); + case -3: logmsg(who,111,ERROR,"key does not match certificate"); + default: break; + } + } else { + switch (ssl_certkey(ctx,certfile,keyfile,passwd_cb)) { + case -1: logmsg(who,111,ERROR,"unable to load certificate"); + case -2: logmsg(who,111,ERROR,"unable to load key"); + case -3: logmsg(who,111,ERROR,"key does not match certificate"); + default: break; + } + } + + if (flagclientcert && !ssl_ca(ctx,cafile,cadir,verifydepth)) + logmsg(who,111,ERROR,"unable to load CA list"); + + if (!ssl_cca(ctx,ccafile)) + logmsg(who,111,ERROR,"unable to load client CA list"); + + if (!ssl_params_rsa(ctx,rsalen)) + logmsg(who,111,ERROR,"unable to set RSA parameters"); + if (!ssl_params_dh(ctx,dhfile)) + logmsg(who,111,ERROR,"unable to set DH parameters"); + + if (flagafter) { + if (gid) if (prot_gid(gid) == -1) + logmsg(who,111,FATAL,"unable to set gid"); + if (uid) if (prot_uid(uid) == -1) + logmsg(who,111,FATAL,"unable to set uid"); + } + + if (!ssl_ciphers(ctx,ciphers)) + logmsg(who,111,ERROR,"unable to set cipher list"); + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + strnum2[fmt_ulong(strnum2,rsalen)] = 0; + log_who(who,B("ciphers ",strnum," ",(char *)ciphers)); + log_who(who,B("cafile ",strnum," ",(char *)cafile)); + log_who(who,B("ccafile ",strnum," ",(char *)ccafile)); + log_who(who,B("cadir ",strnum," ",(char *)cadir)); + log_who(who,B("certchainfile ",strnum," ",(char *)certchainfile)); + log_who(who,B("cert ",strnum," ",(char *)certfile)); + log_who(who,B("key ",strnum," ",(char *)keyfile)); + /* XXX */ + log_who(who,B("dhparam ",strnum," ",(char *)dhfile," ",strnum2)); + } + + close(0); + close(1); + printstatus(); + + for (;;) { + int pause_ret, read_ret; + if (!flagexit) spawn(s,argc,argv); + + sig_unblock(sig_child); + io[0].fd = selfpipe[0]; + io[0].events = IOPAUSE_READ; + taia_now(&stamp); + taia_uint(&deadline,3600); + taia_add(&deadline,&stamp,&deadline); + pause_ret = iopause(io,1,&deadline,&stamp); + sig_block(sig_child); + + if (flagexit && !numchildren) _exit(0); + while ((read_ret = buffer_unixread(selfpipe[0],&ch,1)) == 1) + ; + if ((pause_ret > 0) && (read_ret == 0)) { + flagexit = 1; + --numchildren; + } + if (flagexit && !numchildren) _exit(0); + } +} |