int write_fifodir(char *dirname, stralloc *sa, void (*oaw_func)(char *, stralloc *)) { DIR *dir = NULL; stralloc name = {0}; struct dirent *x = NULL; static struct stat st; /* read directory */ dir = opendir(dirname); if(dir == NULL) { strerr_warn3("can't opendir() ", dirname, ": ", &strerr_sys); return -1; } while (x = readdir(dir)) { if(x == NULL) { strerr_warn3("can't readdir() ", dirname, ": ", &strerr_sys); if(name.a) stralloc_free(&name); return -1; } /* Ignore everything starting with a . */ if(x->d_name[0] != '.') { stralloc_copys(&name, dirname); stralloc_cats(&name, "/"); stralloc_cats(&name, x->d_name); stralloc_0(&name); if(stat(name.s, &st) == -1) { strerr_warn2("can't stat ", name.s, &strerr_sys); } if(S_ISFIFO(st.st_mode)) { oaw_func(name.s, sa); } else { buffer_puts(buffer_2, "ddnsd: warning: "); buffer_puts(buffer_2, name.s); buffer_puts(buffer_2, " is no fifo, ignoring\n"); buffer_flush(buffer_2); } } } closedir(dir); return 0; }
void openandwrite(char *filename, stralloc *sa) { int fdfifo; /* we need this to keep the fifo from beeing closed */ fdfifo = open_write(filename); if (fdfifo == -1) strerr_warn3("ddnsd: unable to open ", filename, "for writing: ", &strerr_sys); // XXX is 5 second timeout a good idea? if(timeoutwrite(5, fdfifo, sa->s, sa->len) != sa->len) strerr_warn3("can't write to fifo ", filename, ": ", &strerr_sys); close(fdfifo); }
/* filedandler for fill_db() */ int readfileintodb(char *file, time_t ctime) { uint32 uid = 0; uint32 t; int fd; int match = 1; int linenum; fd = open_read(file); if(fd == -1) { strerr_warn3("unable to open file: ", file, " ", &strerr_sys); return -1; } buffer_init(&rb, read, fd, rbspace, sizeof rbspace); /* The file might contain references to more than one user id, therefore we work through all lines */ linenum = 0; while(match) { ++linenum; if(getln(&rb, &line, &match, '\n') == -1) { strerr_warn3("unable to read line: ", file, " ", &strerr_sys); return -1; } /* skip empty lines and comments */ if(!line.len) continue; if(line.s[0] == '#') continue; handle_line(&line, 's'); } close(fd); return 0; }
int main (int argc, const char * const *argv, char * const *envp) { const char * prog[2]; int pid, pid2; int wstat; int st; iopause_fd x; #ifndef IOPAUSE_POLL fd_set rfds; struct timeval t; #endif char ch; int ttyfd; struct stat s; if (getpid() != 1) strerr_die2x(111, FATAL, "must be run as process no 1."); setsid(); sig_block(sig_alarm); sig_block(sig_child); sig_catch(sig_child, sig_child_handler); sig_block(sig_cont); sig_catch(sig_cont, sig_cont_handler); sig_block(sig_hangup); sig_block(sig_int); sig_catch(sig_int, sig_int_handler); sig_block(sig_pipe); sig_block(sig_term); /* console */ if ((ttyfd =open_write("/dev/console")) != -1) { dup2(ttyfd, 0); dup2(ttyfd, 1); dup2(ttyfd, 2); if (ttyfd > 2) close(ttyfd); } /* create selfpipe */ while (pipe(selfpipe) == -1) { strerr_warn2(FATAL, "unable to create selfpipe, pausing: ", &strerr_sys); sleep(5); } coe(selfpipe[0]); coe(selfpipe[1]); ndelay_on(selfpipe[0]); ndelay_on(selfpipe[1]); #ifdef RB_DISABLE_CAD /* activate ctrlaltdel handling, glibc, dietlibc */ if (RB_DISABLE_CAD == 0) reboot_system(0); #endif strerr_warn3(INFO, "$Id: 25da3b86f7bed4038b8a039d2f8e8c9bbcf0822b $", ": booting.", 0); /* runit */ for (st =0; st < 3; st++) { /* if (st == 2) logwtmp("~", "reboot", ""); */ while ((pid =fork()) == -1) { strerr_warn4(FATAL, "unable to fork for \"", stage[st], "\" pausing: ", &strerr_sys); sleep(5); } if (!pid) { /* child */ prog[0] =stage[st]; prog[1] =0; /* stage 1 gets full control of console */ if (st == 0) { if ((ttyfd =open("/dev/console", O_RDWR)) != -1) { #ifdef TIOCSCTTY ioctl(ttyfd, TIOCSCTTY, (char *)0); #endif dup2(ttyfd, 0); if (ttyfd > 2) close(ttyfd); } else strerr_warn2(WARNING, "unable to open /dev/console: ", &strerr_sys); } else setsid(); sig_unblock(sig_alarm); sig_unblock(sig_child); sig_uncatch(sig_child); sig_unblock(sig_cont); sig_ignore(sig_cont); sig_unblock(sig_hangup); sig_unblock(sig_int); sig_uncatch(sig_int); sig_unblock(sig_pipe); sig_unblock(sig_term); strerr_warn3(INFO, "enter stage: ", stage[st], 0); execve(*prog, (char *const *)prog, envp); strerr_die4sys(0, FATAL, "unable to start child: ", stage[st], ": "); } x.fd =selfpipe[0]; x.events =IOPAUSE_READ; for (;;) { int child; sig_unblock(sig_child); sig_unblock(sig_cont); sig_unblock(sig_int); #ifdef IOPAUSE_POLL poll(&x, 1, 14000); #else t.tv_sec =14; t.tv_usec =0; FD_ZERO(&rfds); FD_SET(x.fd, &rfds); select(x.fd +1, &rfds, (fd_set*)0, (fd_set*)0, &t); #endif sig_block(sig_cont); sig_block(sig_child); sig_block(sig_int); while (read(selfpipe[0], &ch, 1) == 1) {} while ((child =wait_nohang(&wstat)) > 0) if (child == pid) break; if (child == -1) { strerr_warn2(WARNING, "wait_nohang, pausing: ", &strerr_sys); sleep(5); } /* reget stderr */ if ((ttyfd =open_write("/dev/console")) != -1) { dup2(ttyfd, 2); if (ttyfd > 2) close(ttyfd); } if (child == pid) { if (wait_exitcode(wstat) != 0) { if (wait_crashed(wstat)) strerr_warn3(WARNING, "child crashed: ", stage[st], 0); else strerr_warn3(WARNING, "child failed: ", stage[st], 0); if (st == 0) /* this is stage 1 */ if (wait_crashed(wstat) || (wait_exitcode(wstat) == 100)) { strerr_warn3(INFO, "leave stage: ", stage[st], 0); strerr_warn2(WARNING, "skipping stage 2...", 0); st++; break; } if (st == 1) /* this is stage 2 */ if (wait_crashed(wstat) || (wait_exitcode(wstat) == 111)) { strerr_warn2(WARNING, "killing all processes in stage 2...", 0); kill(-pid, 9); sleep(5); strerr_warn2(WARNING, "restarting.", 0); st--; break; } } strerr_warn3(INFO, "leave stage: ", stage[st], 0); break; } if (child != 0) { /* collect terminated children */ write(selfpipe[1], "", 1); continue; } /* sig? */ if (!sigc && !sigi) { #ifdef DEBUG strerr_warn2(WARNING, "poll: ", &strerr_sys); #endif continue; } if (st != 1) { strerr_warn2(WARNING, "signals only work in stage 2.", 0); sigc =sigi =0; continue; } if (sigi && (stat(CTRLALTDEL, &s) != -1) && (s.st_mode & S_IXUSR)) { strerr_warn2(INFO, "ctrl-alt-del request...", 0); prog[0] =CTRLALTDEL; prog[1] =0; while ((pid2 =fork()) == -1) { strerr_warn4(FATAL, "unable to fork for \"", CTRLALTDEL, "\" pausing: ", &strerr_sys); sleep(5); } if (!pid2) { /* child */ strerr_warn3(INFO, "enter stage: ", prog[0], 0); execve(*prog, (char *const *) prog, envp); strerr_die4sys(0, FATAL, "unable to start child: ", prog[0], ": "); } if (wait_pid(&wstat, pid2) == -1) strerr_warn2(FATAL, "wait_pid: ", &strerr_sys); if (wait_crashed(wstat)) strerr_warn3(WARNING, "child crashed: ", CTRLALTDEL, 0); strerr_warn3(INFO, "leave stage: ", prog[0], 0); sigi =0; sigc++; } if (sigc && (stat(STOPIT, &s) != -1) && (s.st_mode & S_IXUSR)) { int i; /* unlink(STOPIT); */ chmod(STOPIT, 0); /* kill stage 2 */ #ifdef DEBUG strerr_warn2(WARNING, "sending sigterm...", 0); #endif kill(pid, sig_term); i =0; while (i < 5) { if ((child =wait_nohang(&wstat)) == pid) { #ifdef DEBUG strerr_warn2(WARNING, "stage 2 terminated.", 0); #endif pid =0; break; } if (child) continue; if (child == -1) strerr_warn2(WARNING, "wait_nohang: ", &strerr_sys); #ifdef DEBUG strerr_warn2(WARNING, "waiting...", 0); #endif sleep(1); i++; } if (pid) { /* still there */ strerr_warn2(WARNING, "stage 2 not terminated, sending sigkill...", 0); kill(pid, 9); if (wait_pid(&wstat, pid) == -1) strerr_warn2(WARNING, "wait_pid: ", &strerr_sys); } sigc =0; strerr_warn3(INFO, "leave stage: ", stage[st], 0); /* enter stage 3 */ break; } sigc =sigi =0; #ifdef DEBUG strerr_warn2(WARNING, "no request.", 0); #endif } } /* reget stderr */ if ((ttyfd =open_write("/dev/console")) != -1) { dup2(ttyfd, 2); if (ttyfd > 2) close(ttyfd); } #ifdef RB_AUTOBOOT /* fallthrough stage 3 */ strerr_warn2(INFO, "sending KILL signal to all processes...", 0); kill(-1, SIGKILL); pid =fork(); switch (pid) { case 0: case -1: if ((stat(REBOOT, &s) != -1) && (s.st_mode & S_IXUSR)) { strerr_warn2(INFO, "system reboot.", 0); sync(); reboot_system(RB_AUTOBOOT); } else { #ifdef RB_POWER_OFF strerr_warn2(INFO, "power off...", 0); sync(); reboot_system(RB_POWER_OFF); sleep(2); #endif #ifdef RB_HALT_SYSTEM strerr_warn2(INFO, "system halt.", 0); sync(); reboot_system(RB_HALT_SYSTEM); #else #ifdef RB_HALT strerr_warn2(INFO, "system halt.", 0); sync(); reboot_system(RB_HALT); #else strerr_warn2(INFO, "system reboot.", 0); sync(); reboot_system(RB_AUTOBOOT); #endif #endif } if (pid == 0) _exit(0); break; default: sig_unblock(sig_child); while (wait_pid(0, pid) == -1); } #endif for (;;) sig_pause(); /* not reached */ strerr_die2x(0, INFO, "exit."); return(0); }
/* this is out work routine which is called by DJBs server code */ int respond(char *q, char qtype[2]) { int flaga; int flagaaaa; int flagloc; char ip[IP6_FMT]; stralloc filename = { 0 }; int fd; buffer b; char bspace[1024]; static stralloc line; int match = 1; unsigned long linenum = 0; int data = 0; stralloc f[NUMFIELDS] = {{0}}; /* check what the client is requesting */ flaga = byte_equal(qtype,2,DNS_T_A); flagloc = byte_equal(qtype,2,DNS_T_LOC); flagaaaa = byte_equal(qtype,2,DNS_T_AAAA); if (byte_equal(qtype,2,DNS_T_ANY)) flaga = flagloc = flagaaaa = 1; /* find out in which file we should look */ query2filename(q, &filename); buffer_put(buffer_2, filename.s, filename.len); buffer_puts(buffer_2, "\n"); buffer_flush(buffer_2); fd = open_read(filename.s); if (fd == -1) { strerr_warn3("unable to open file: ", filename.s, ": ", &strerr_sys); match = 0; } buffer_init(&b, read, fd, bspace, sizeof bspace); /* Work through the file and handout the data. */ while(match) { ++linenum; if(getln(&b, &line, &match, '\n') == -1) { strerr_warn1("unable to read line: ", &strerr_sys); break; } /* clean up line end */ stralloc_cleanlineend(&line); /* skip comments & empty lines */ if(line.s[0] == '#') continue; if(line.s[0] == 0) continue; /* seperate fields */ fieldsep(f, NUMFIELDS, &line, ','); /* IPv4 */ if(f[0].s[0] == '=') { if (flaga) { ip4_scan(f[2].s, ip); data++; /* put type and ttl (60s) */ if (!response_rstart(q, DNS_T_A, "\0\0\0\74")) return 0; /* put ip */ if (!response_addbytes(ip, 4)) return 0; /* record finished */ response_rfinish(RESPONSE_ANSWER); } } /* IPv6 */ if(f[0].s[0] == '6') { if (flagaaaa) { ip6_scan(f[0].s, ip); data++; /* put type and ttl (60s) */ if (!response_rstart(q, DNS_T_AAAA, "\0\0\0\74")) return 0; /* put ip */ if (!response_addbytes(ip, 16)) return 0; /* record finished */ response_rfinish(RESPONSE_ANSWER); } } /* LOC */ if(f[0].s[0] == 'L') { if (flagloc) { txtparse(&f[2]); if(f[2].len <= 16) { buffer_puts(buffer_2, "filedns: warning: LOC record seems to short\n"); buffer_flush(buffer_2); } data++; /* put type and ttl (60s) */ if (!response_rstart(q, DNS_T_LOC, "\0\0\0\74")) return 0; /* put ip */ if (!response_addbytes(f[2].s, 16)) return 0; /* record finished */ response_rfinish(RESPONSE_ANSWER); } } } /* Disclaimer ;-) */ if (!response_rstart(q, DNS_T_TXT, "\0\0\0\74")) return 0; if (!response_addbytes("this is a response from an alpha quality dns-server", 51)) return 0; response_rfinish(RESPONSE_ADDITIONAL); if (!response_rstart(q, DNS_T_TXT, "\0\0\0\74")) return 0; if (!response_addbytes("filednes 0.00 - if problems arise contact [email protected]", 54)) return 0; response_rfinish(RESPONSE_ADDITIONAL); // if (flaga || flagptr) // { // if (dd(q,"",ip) == 4) // { // if (flaga) // { // if (!response_rstart(q,DNS_T_A,"\0\12\0\0")) return 0; // if (!response_addbytes(ip,4)) return 0; // response_rfinish(RESPONSE_ANSWER); // } // return 1; // } // j = dd(q,"\7in-addr\4arpa",ip); // if (j >= 0) // { if(data > 0) return 1; /* nothing found */ buffer_puts(buffer_2, "notfound\n"); buffer_flush(buffer_2); // XXX: this is somehow broken /* response 0-1 is transaction id */ /* set response flags */ /* clear authority bit */ response[2] &= ~4; /* clear last 4 bits */ response[3] &= ~15; /* flag not found */ response[3] |= 3; /* response[4..5]: nr of questions * response[6..7]: nr of answers rr * response[8..9]: nr of authority rr * response[10..11]: nr of additional rr */ return 1; }
void doit(int t) { int fakev4=0; int j; SSL *ssl; int wstat; uint32 scope_id; int sslctl[2]; char *s; unsigned long tmp_long; char sslctl_cmd; stralloc ssl_env = { 0 }; buffer ssl_env_buf; if (pipe(pi) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (pipe(po) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sslctl) == -1) strerr_die2sys(111,DROP,"unable to create socketpair: "); switch(fork()) { case -1: strerr_die2sys(111,DROP,"unable to fork: "); case 0: /* Child */ break; default: /* Parent */ close(pi[0]); close(po[1]); close(sslctl[1]); if ((s=env_get("SSL_CHROOT"))) if (chroot(s) == -1) strerr_die2x(111,DROPSSL,"unable to chroot"); if ((s=env_get("SSL_GID"))) { scan_ulong(s,&tmp_long); gid = tmp_long; } if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,DROPSSL,"unable to set gid: "); if ((s=env_get("SSL_UID"))) { scan_ulong(s,&tmp_long); uid = tmp_long; } if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,DROPSSL,"unable to set uid: "); /* This will exit on a fatal error or if the client quits * without activating SSL */ sslctl_cmd = ucspitls_master_wait_for_activation(sslctl[0]); /* If we got here, SSL must have been activated */ ssl = ssl_new(ctx,t); if (!ssl) strerr_die2x(111,DROP,"unable to create SSL instance"); if (ndelay_on(t) == -1) strerr_die2sys(111,DROP,"unable to set socket options: "); if (ssl_timeoutaccept(ssl,ssltimeout) == -1) strerr_die3x(111,DROP,"unable to accept SSL: ",ssl_error_str(ssl_errno)); if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn3("sslserver: ssl ",strnum," accept ",0); } if (flagclientcert) { switch(ssl_verify(ssl,verifyhost)) { case -1: strerr_die2x(111,DROP,"unable to verify client certificate"); case -2: strerr_die2x(111,DROP,"no client certificate"); case -3: strerr_die2x(111,DROP,"client name does not match certificate"); default: break; } } if (sslctl_cmd == 'Y') { ssl_server_env(ssl, &ssl_env); stralloc_0(&ssl_env); /* Add another NUL */ buffer_init(&ssl_env_buf,buffer_unixwrite,sslctl[0],NULL,0); if (buffer_putflush(&ssl_env_buf, ssl_env.s, ssl_env.len) == -1) { strerr_die2sys(111, FATAL, "unable to write SSL environment: "); } } else if (sslctl_cmd != 'y') { strerr_die2x(111,DROP,"Protocol error on SSL control descriptor: invalid command character read"); } if (close(sslctl[0]) != 0) { strerr_die2sys(111, DROP, "Error closing SSL control socket: "); } if (ssl_io(ssl,pi[1],po[0],io_opt) != 0) strerr_die3x(111,DROP,"unable to speak SSL: ",ssl_error_str(ssl_errno)); if (wait_nohang(&wstat) > 0) _exit(wait_exitcode(wstat)); ssl_close(ssl); _exit(0); } /* Child-only below this point */ if (close(sslctl[0]) != 0) { strerr_die2sys(111, DROP, "Error closing SSL control socket: "); } if (!forcev6 && ip6_isv4mapped(remoteip)) fakev4=1; if (fakev4) remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; else remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn4("sslserver: pid ",strnum," from ",remoteipstr,0); } if (socket_local6(t,localip,&localport,&scope_id) == -1) strerr_die2sys(111,DROP,"unable to get local address: "); if (fakev4) localipstr[ip4_fmt(localipstr,localip+12)] = 0; else localipstr[ip6_fmt(localipstr,localip)] = 0; remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) if (dns_name6(&localhostsa,localip) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) drop_nomem(); localhost = localhostsa.s; } env("PROTO",fakev4?"SSL":"SSL6"); env("SSLLOCALIP",localipstr); env("SSL6LOCALIP",localipstr); env("SSLLOCALPORT",localportstr); env("SSL6LOCALPORT",localportstr); env("SSLLOCALHOST",localhost); env("SSL6LOCALHOST",localhost); if (!fakev4 && scope_id) env("SSL6INTERFACE",socket_getifname(scope_id)); if (flagtcpenv) { env("TCPLOCALIP",localipstr); env("TCP6LOCALIP",localipstr); env("TCPLOCALPORT",localportstr); env("TCP6LOCALPORT",localportstr); env("TCPLOCALHOST",localhost); env("TCP6LOCALHOST",localhost); if (!fakev4 && scope_id) env("TCP6INTERFACE",socket_getifname(scope_id)); } if (flagremotehost) if (dns_name6(&remotehostsa,remoteip) == 0) if (remotehostsa.len) { if (flagparanoid) { verifyhost = remoteipstr; 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 (!flagparanoid) { if (!stralloc_0(&remotehostsa)) drop_nomem(); remotehost = remotehostsa.s; verifyhost = remotehostsa.s; } } env("SSLREMOTEIP",remoteipstr); env("SSL6REMOTEIP",remoteipstr); remoteipstr[ip6_fmt(remoteipstr,remoteip)]=0; env("SSLREMOTEPORT",remoteportstr); env("SSL6REMOTEPORT",remoteportstr); env("SSLREMOTEHOST",remotehost); env("SSL6REMOTEHOST",remotehost); if (flagtcpenv) { env("TCPREMOTEIP",remoteipstr); env("TCP6REMOTEIP",remoteipstr); env("TCPREMOTEPORT",remoteportstr); env("TCP6REMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); env("TCP6REMOTEHOST",remotehost); } if (flagremoteinfo) { if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) flagremoteinfo = 0; if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); } env("SSLREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); env("SSL6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (flagtcpenv) { env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); env("TCP6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); } if (fnrules) { int fdrules; fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); if (!flagallownorules) drop_rules(); } else { int fakev4=0; char* temp; if (!forcev6 && ip6_isv4mapped(remoteip)) fakev4=1; if (fakev4) temp=remoteipstr+7; else temp=remoteipstr; if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"sslserver: ")) 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) _exit(100); if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,FATAL,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,FATAL,"unable to set uid: "); close(pi[1]); close(po[0]); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); if (fcntl(sslctl[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,sslctl[1])]=0; setenv("SSLCTLFD",strnum,1); if (fcntl(pi[0],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,pi[0])]=0; setenv("SSLREADFD",strnum,1); if (fcntl(po[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,po[1])]=0; setenv("SSLWRITEFD",strnum,1); if (flagsslwait) { if (fd_copy(0,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_copy(1,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } else { if (fd_move(0,pi[0]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_move(1,po[1]) == -1) strerr_die2sys(111,DROP,"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) strerr_die2sys(111,DROP,"unable to print banner: "); } if (!flagsslwait) { strnum[fmt_ulong(strnum,flagsslenv)] = 0; strerr_warn2("flagsslenv: ", strnum, 0); ucspitls(flagsslenv,0,1); } pathexec(prog); strerr_die4sys(111,DROP,"unable to run ",*prog,": "); }
void doit(int t) { int j; SSL *ssl; int wstat; int sslctl[2]; char *s; unsigned long tmp_long; char ssl_cmd; stralloc ssl_env = { 0 }; int bytesleft; char envbuf[8192]; int childpid; if (pipe(pi) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (pipe(po) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sslctl) == -1) strerr_die2sys(111,DROP,"unable to create socketpair: "); if ((j = ip_fmt(&remoteipsa,&remoteaddr))) strerr_die3x(111,DROP,"unable to print remote ip",gai_strerror(j)); if (flagremotehost) { if (dns_name(&remotehostsa,&remoteaddr) == 0) if (remotehostsa.len) { if (flagparanoid) { struct addrinfo *reverse, hints = {0}; verifyhost = remoteipsa.s; hints.ai_family = remoteaddr.sa4.sin_family; if (remoteaddr.sa6.sin6_family == AF_INET6) { hints.ai_flags = AI_V4MAPPED | AI_ALL; } if (getaddrinfo(remotehostsa.s, NULL, &hints, &reverse) == 0) { hints.ai_next = reverse; while (hints.ai_next) { if (hints.ai_next->ai_family == AF_INET && remoteaddr.sa4.sin_family == AF_INET && byte_equal(&remoteaddr.sa4.sin_addr, 4, &((struct sockaddr_in*) hints.ai_next->ai_addr)->sin_addr) || hints.ai_next->ai_family == AF_INET6 && remoteaddr.sa6.sin6_family == AF_INET6 && byte_equal(remoteaddr.sa6.sin6_addr.s6_addr, 16, &((struct sockaddr_in6*) hints.ai_next->ai_addr)->sin6_addr.s6_addr)) { flagparanoid = 0; break; } hints.ai_next = hints.ai_next->ai_next; } freeaddrinfo(reverse); } } if (!flagparanoid) { remotehost = remotehostsa.s; verifyhost = remotehostsa.s; } } } switch(childpid=fork()) { case -1: strerr_die2sys(111,DROP,"unable to fork: "); case 0: /* Child */ close(sslctl[0]); break; default: /* Parent */ close(pi[0]); close(po[1]); close(sslctl[1]); if ((s=env_get("SSL_CHROOT"))) if (chroot(s) == -1) { kill(childpid, SIGTERM); strerr_die2x(111,DROP,"unable to chroot"); } if ((s=env_get("SSL_GID"))) { scan_ulong(s,&tmp_long); gid = tmp_long; } if (gid) if (prot_gid(gid) == -1) { kill(childpid, SIGTERM); strerr_die2sys(111,FATAL,"unable to set gid: "); } if ((s=env_get("SSL_UID"))) { scan_ulong(s,&tmp_long); uid = tmp_long; } if (uid) if (prot_uid(uid) == -1) { kill(childpid, SIGTERM); strerr_die2sys(111,FATAL,"unable to set uid: "); } /* Read the TLS command socket. This will block until/unless * TLS is requested. */ if (read(sslctl[0],&ssl_cmd,1) == 1) { ssl = ssl_new(ctx,t); if (!ssl) { kill(childpid, SIGTERM); strerr_die2x(111,DROP,"unable to create SSL instance"); } if (ndelay_on(t) == -1) { kill(childpid, SIGTERM); strerr_die2sys(111,DROP,"unable to set socket options: "); } if (ssl_timeoutaccept(ssl,ssltimeout) == -1) { kill(childpid, SIGTERM); strerr_die3x(111,DROP,"unable to accept SSL: ",ssl_error_str(ssl_errno)); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn3("sslserver: ssl ",strnum," accept ",0); } if (flagclientcert) { switch(ssl_verify(ssl,verifyhost)) { case -1: kill(childpid, SIGTERM); strerr_die2x(111,DROP,"unable to verify client certificate"); case -2: kill(childpid, SIGTERM); strerr_die2x(111,DROP,"no client certificate"); case -3: kill(childpid, SIGTERM); strerr_die3x(111,DROP,"certificate name does not match client fqdn: ",verifyhost); default: break; } } if (ssl_cmd == 'Y') { ssl_server_env(ssl, &ssl_env); if(!stralloc_0(&ssl_env)) drop_nomem(); /* Add another NUL */ env("SSLCTL",ssl_env.s); for(bytesleft = ssl_env.len; bytesleft>0; bytesleft-=j) if ( (j=write(sslctl[0], ssl_env.s, bytesleft)) < 0) { kill(childpid, SIGTERM); strerr_die2sys(111, FATAL, "unable to write SSL environment: "); } } if (ssl_cmd == 'Y' || ssl_cmd == 'y') { if (ssl_io(ssl,pi[1],po[0],progtimeout) != 0) { kill(childpid, SIGTERM); strerr_die3x(111,DROP,"unable to speak SSL: ",ssl_error_str(ssl_errno)); } if (wait_nohang(&wstat) > 0) _exit(wait_exitcode(wstat)); ssl_close(ssl); } kill(childpid, SIGTERM); _exit(0); } /* Child-only below this point */ if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn4("sslserver: pid ",strnum," from ",remoteipsa.s,0); } if (socket_local(t,&localaddr,&localport) == -1) strerr_die2sys(111,DROP,"unable to get local address: "); if ((j = ip_fmt(&localipsa,&localaddr))) strerr_die3x(111,DROP,"unable to print local address: ",gai_strerror(j)); remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) if (dns_name(&localhostsa,&localaddr) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) drop_nomem(); localhost = localhostsa.s; } /* If remoteipsa.s contain ':' colon character will assume it is IPv6 */ if (byte_chr(remoteipsa.s, remoteipsa.len, ':') < remoteipsa.len) env("PROTO","SSL6"); else env("PROTO","SSL"); env("SSLLOCALIP",localipsa.s); env("SSLLOCALPORT",localportstr); env("SSLLOCALHOST",localhost); if (flagtcpenv) { env("TCPLOCALIP",localipsa.s); env("TCPLOCALPORT",localportstr); env("TCPLOCALHOST",localhost); } env("SSLREMOTEIP",remoteipsa.s); env("SSLREMOTEPORT",remoteportstr); env("SSLREMOTEHOST",remotehost); if (flagtcpenv) { env("TCPREMOTEIP",remoteipsa.s); env("TCPREMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); } if (flagremoteinfo) { if (remoteinfo(&tcpremoteinfo,&remoteaddr,&localaddr,timeout) == -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; fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); if (!flagallownorules) drop_rules(); } else { if (rules(found,fdrules,&remoteaddr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"sslserver: ")) drop_nomem(); safecats(flagdeny ? "deny" : "ok"); cats(" "); safecats(strnum); cats(" "); if (localhost) safecats(localhost); cats(":"); safecats(localipsa.s); cats(":"); safecats(localportstr); cats(" "); if (remotehost) safecats(remotehost); cats(":"); safecats(remoteipsa.s); cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); safecats(remoteportstr); cats("\n"); buffer_putflush(buffer_2,tmp.s,tmp.len); } if (flagdeny) _exit(100); if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,FATAL,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,FATAL,"unable to set uid: "); close(pi[1]); close(po[0]); close(sslctl[0]); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); if (fcntl(sslctl[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,sslctl[1])]=0; env("SSLCTLFD",strnum); if (fcntl(pi[0],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,pi[0])]=0; env("SSLREADFD",strnum); if (fcntl(po[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,po[1])]=0; env("SSLWRITEFD",strnum); if (flagsslwait) { if (fd_copy(0,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_copy(1,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } else { if (fd_move(0,pi[0]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_move(1,po[1]) == -1) strerr_die2sys(111,DROP,"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) strerr_die2sys(111,DROP,"unable to print banner: "); } if (!flagsslwait) { ssl_cmd = flagsslenv ? 'Y' : 'y'; if (write(sslctl[1], &ssl_cmd, 1) < 1) strerr_die2sys(111,DROP,"unable to start SSL: "); if (flagsslenv) { while ((j=read(sslctl[1],envbuf,8192)) > 0) { stralloc_catb(&ssl_env,envbuf,j); if (ssl_env.len >= 2 && ssl_env.s[ssl_env.len-2]==0 && ssl_env.s[ssl_env.len-1]==0) break; } if (j < 0) strerr_die2sys(111,DROP,"unable to read SSL environment: "); pathexec_multienv(&ssl_env); } } pathexec(prog); strerr_die4sys(111,DROP,"unable to run ",*prog,": "); }
void fatal(char *m1) { strerr_warn3(FATAL, m1, ": ", &strerr_sys); done(lsb ? 151 : 100); }
int main(int argc, const char * const *argv) { int opt; unsigned long sec =600; int verbose =0; int doexit =0; int dokill =0; int wdir; int fd; char status[20]; int r; unsigned long pid; struct tai start; struct tai now; progname =*argv; while ((opt =getopt(argc, argv, "t:xkvV")) != opteof) { switch(opt) { case 't': scan_ulong(optarg, &sec); if ((sec < 1) || (sec > 6000)) usage(); break; case 'x': doexit =1; break; case 'k': dokill =1; break; case 'v': verbose =1; break; case 'V': strerr_warn1(VERSION, 0); case '?': usage(); } } argv +=optind; if (! argv || ! *argv) usage(); if ((wdir =open_read(".")) == -1) fatal("unable to open current working directory"); for (dir =argv; *dir; ++dir) { if (dir != argv) if (fchdir(wdir) == -1) fatal("unable to switch to starting directory"); if (chdir(*dir) == -1) continue; /* bummer */ if ((fd =open_write("supervise/control")) == -1) continue; /* bummer */ if (write(fd, "dx", 1 +doexit) != (1 +doexit)) { close(fd); continue; /* bummer */ } close(fd); } dir =argv; tai_now(&start); while (*dir) { if (fchdir(wdir) == -1) fatal("unable to switch to starting directory"); if (chdir(*dir) == -1) { warn(*dir, ": unable to change directory: ", &strerr_sys); continue; } if ((fd =open_write("supervise/ok")) == -1) { if (errno == error_nodevice) { if (verbose) strerr_warn3(INFO, *dir, ": runsv not running.", 0); dir++; } else warn(*dir, ": unable to open supervise/ok: ", &strerr_sys); continue; } close(fd); if ((fd =open_read("supervise/status")) == -1) { warn(*dir, "unable to open supervise/status: ", &strerr_sys); continue; } r =buffer_unixread(fd, status, 20); close(fd); if ((r < 18) || (r == 19)) { /* supervise compatibility */ if (r == -1) warn(*dir, "unable to read supervise/status: ", &strerr_sys); else warn(*dir, ": unable to read supervise/status: bad format.", 0); continue; } pid =(unsigned char)status[15]; pid <<=8; pid +=(unsigned char)status[14]; pid <<=8; pid +=(unsigned char)status[13]; pid <<=8; pid +=(unsigned char)status[12]; if (! doexit && ! pid) { /* ok, service is down */ if (verbose) strerr_warn3(INFO, *dir, ": down.", 0); dir++; continue; } if (status[17] != 'd') { /* catch previous failures */ if ((fd =open_write("supervise/control")) == -1) { warn(*dir, ": unable to open supervise/control: ", &strerr_sys); continue; } if (write(fd, "dx", 1 +doexit) != (1 +doexit)) { warn(*dir, ": unable to write to supervise/control: ", &strerr_sys); close(fd); continue; } close(fd); } tai_now(&now); tai_sub(&now, &now, &start); if (tai_approx(&now) >= sec) { /* timeout */ if (verbose) strerr_warn2(INFO, "timeout.", 0); if (dokill) { if (chdir(*dir) == -1) { warn(*dir, ": unable to change directory: ", &strerr_sys); continue; } if ((fd =open_write("supervise/control")) == -1) { if (errno == error_nodevice) { if (verbose) strerr_warn3(INFO, *dir, ": runsv not running.", 0); dir++; } else warn(*argv, ": unable to open supervise/control: ", &strerr_sys); continue; } if (write(fd, "k", 1) != 1) warn(*argv, ": unable to write to supervise/control: ", &strerr_sys); else strerr_warn3(INFO, *dir, ": killed.", 0); close(fd); dir++; if (! *dir) _exit(111); continue; } _exit(111); } sleep(1); } if (fchdir(wdir) == -1) strerr_warn2(WARN, "unable to switch to starting directory: ", &strerr_sys); close(wdir); if (rc > 100) rc =100; _exit(rc); }
void warn(const char *s1, const char *s2, struct strerr *e) { dir++; rc++; strerr_warn3(WARN, s1, s2, e); }
void warn(char *m0) { strerr_warn3(WARNING, m0, ": ", &strerr_sys); }