int main(int argc,const char *const *argv,const char *const *envp) { struct passwd *pw; const char *account; char strnum[FMT_ULONG]; account = *++argv; if (!account || !*++argv) usage(); pw = getpwnam(account); if (!pw) strerr_die3x(111,FATAL,"unknown account ",account); if (!pathexec_env("HOME",pw->pw_dir)) nomem(); if (!pathexec_env("SHELL",pw->pw_shell)) nomem(); if (!pathexec_env("USER",pw->pw_name)) nomem(); strnum[fmt_ulong(strnum,pw->pw_gid)] = 0; if (!pathexec_env("GID",strnum)) nomem(); strnum[fmt_ulong(strnum,pw->pw_uid)] = 0; if (!pathexec_env("UID",strnum)) nomem(); if (chdir(pw->pw_dir) != 0) strerr_die3sys(111,FATAL,"unable to chdir to ", pw->pw_dir); if (prot_gid(pw->pw_gid) == -1) strerr_die2sys(111,FATAL,"unable to setgid"); if (prot_gids(pw->pw_name, pw->pw_gid) == -1) strerr_die2sys(111,FATAL,"unable to initgroups"); if (prot_uid(pw->pw_uid) == -1) strerr_die2sys(111,FATAL,"unable to setuid"); pathexec_run(*argv,argv,envp); strerr_die3sys(111,FATAL,"unable to run ",*argv); }
void didentd_init() { /* chroot() to /proc/net/ and switch to $UID:$GID */ char *x; unsigned long id; if (chdir("/proc/net/") == -1) strerr_die2sys(111,FATAL,"unable to chdir to '/proc/net/': "); if (chroot(".") == -1) strerr_die2sys(111,FATAL,"unable to chdir to '/proc/net/': "); x = env_get("GID"); if (!x) strerr_die2x(111,FATAL,"$GID not set"); scan_ulong(x,&id); if (prot_gid((int) id) == -1) strerr_die2sys(111,FATAL,"unable to setgid: "); x = env_get("UID"); if (!x) strerr_die2x(111,FATAL,"$UID not set"); scan_ulong(x,&id); if (prot_uid((int) id) == -1) strerr_die2sys(111,FATAL,"unable to setuid: "); }
void change_uid(unsigned int uid, unsigned int gid) { unsigned int id; id = geteuid(); if (id != 0 && (id == uid || uid == (unsigned int)-1)) { /* not running as root so return */ logit(32, "change_uid: already running non root\n"); return; } if (uid == (unsigned int)-1 && gid == (unsigned int)-1) { /* run as non-privileged user qmaild group nofiles */ uid = auto_uidd; gid = auto_gidn; } /* first set the group id */ if (prot_gid(gid) == -1) auth_error(ERRNO); logit(32, "setgid succeeded (%i)\n", gid); /* ... then the user id */ if (prot_uid(uid) == -1) auth_error(ERRNO); logit(32, "setuid succeeded (%i)\n", uid); /* ... now check that we are realy not running as root */ if (!getuid()) auth_error(FAILED); }
void didentd_init() { char *x; unsigned long id; x = env_get("ROOT"); if (!x) strerr_die2x(111,FATAL,"$ROOT not set"); if (chdir(x) == -1) strerr_die4sys(111,FATAL,"unable to chdir to ",x,": "); x = env_get("GID"); if (!x) strerr_die2x(111,FATAL,"$GID not set"); scan_ulong(x,&id); if (prot_gid((int) id) == -1) strerr_die2sys(111,FATAL,"unable to setgid: "); x = env_get("UID"); if (!x) strerr_die2x(111,FATAL,"$UID not set"); scan_ulong(x,&id); if (prot_uid((int) id) == -1) strerr_die2sys(111,FATAL,"unable to setuid: "); }
int main(int argc,const char *const *argv,const char *const *envp) { account = *++argv; if (!account || !*++argv) strerr_die1x(100,"setuidgid: usage: setuidgid account child"); pw = getpwnam(account); if (!pw) strerr_die3x(111,FATAL,"unknown account ",account); if (prot_gid(pw->pw_gid) == -1) strerr_die2sys(111,FATAL,"unable to setgid: "); if (prot_uid(pw->pw_uid) == -1) strerr_die2sys(111,FATAL,"unable to setuid: "); pathexec_run(*argv,argv,envp); strerr_die4sys(111,FATAL,"unable to run ",*argv,": "); }
int main(int argc,char **argv) { if (chdir("/") == -1) die(errno); umask(077); if (prot_gid(auto_gidq) == -1) die(errno); if (fd_copy(2,0) == -1) die(errno); if (fd_copy(3,0) == -1) die(errno); if (fd_copy(4,0) == -1) die(errno); if (fd_copy(5,0) == -1) die(errno); if (fd_copy(6,0) == -1) die(errno); if (argv[1]) { qlargs[1] = argv[1]; ++argv; } if (argv[1]) { if (pipe(pi0) == -1) die(errno); switch(fork()) { case -1: die(errno); case 0: if (prot_gid(auto_gidn) == -1) die(errno); if (prot_uid(auto_uidl) == -1) die(errno); close(pi0[1]); if (fd_move(0,pi0[0]) == -1) die(errno); close23456(); execvp(argv[1],argv + 1); die(errno); } close(pi0[0]); if (fd_move(1,pi0[1]) == -1) die(errno); } if (pipe(pi1) == -1) die(errno); if (pipe(pi2) == -1) die(errno); if (pipe(pi3) == -1) die(errno); if (pipe(pi4) == -1) die(errno); if (pipe(pi5) == -1) die(errno); if (pipe(pi6) == -1) die(errno); /* start qmail-lspawn */ switch(fork()) { case -1: die(errno); case 0: if (fd_copy(0,pi1[0]) == -1) die(errno); if (fd_copy(1,pi2[1]) == -1) die(errno); close23456(); closepipes(); execvp(*qlargs,qlargs); die(errno); } /* start qmail-rspawn */ switch(fork()) { case -1: die(errno); case 0: if (prot_uid(auto_uidr) == -1) die(errno); if (fd_copy(0,pi3[0]) == -1) die(errno); if (fd_copy(1,pi4[1]) == -1) die(errno); close23456(); closepipes(); execvp(*qrargs,qrargs); die(errno); } /* start qmail-clean */ switch(fork()) { case -1: die(errno); case 0: if (prot_uid(auto_uidq) == -1) die(errno); if (fd_copy(0,pi5[0]) == -1) die(errno); if (fd_copy(1,pi6[1]) == -1) die(errno); close23456(); closepipes(); execvp(*qcargs,qcargs); die(errno); } if (prot_uid(auto_uids) == -1) die(errno); if (fd_copy(0,1) == -1) die(errno); if (fd_copy(1,pi1[1]) == -1) die(errno); if (fd_copy(2,pi2[0]) == -1) die(errno); if (fd_copy(3,pi3[1]) == -1) die(errno); if (fd_copy(4,pi4[0]) == -1) die(errno); if (fd_copy(5,pi5[1]) == -1) die(errno); if (fd_copy(6,pi6[0]) == -1) die(errno); closepipes(); execvp(*qsargs,qsargs); /* start qmail-send */ die(errno); return(0); /* never reached */ }
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,": "); }
int main(int argc,char **argv) { char *hostname; // char *portname; int opt; struct servent *se; char *x; unsigned long u; int s; int t; while ((opt = getopt(argc,argv,"4dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != 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 '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 'I': netif=socket_getifidx(optarg); break; case '1': flag1 = 1; break; // case '4': noipv6 = 1; break; case '4': ipv4socket = 1; break; // case '6': forcev6 = 1; break; case 'l': localhost = optarg; break; default: usage(); } argc -= optind; argv += optind; if (!verbosity) buffer_2->fd = -1; hostname = *argv++; if (!hostname) usage(); if (str_equal(hostname,"")) hostname = "0"; x = *argv++; if (!x) usage(); if (!x[scan_ulong(x,&u)]) localport = u; else { se = getservbyname(x,"tcp"); if (!se) errint(EHARD,B("unable to figure out port number for ",x)); uint16_unpack_big((char*)&se->s_port,&localport); } if (!*argv) usage(); sig_block(sig_child); sig_catch(sig_child,sigchld); sig_catch(sig_term,sigterm); sig_ignore(sig_pipe); if (str_equal(hostname,"0")) { byte_zero(localip,sizeof localip); } else { if (!stralloc_copys(&tmp,hostname)) errmem; if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1) errint(EHARD,B("temporarily unable to figure out IP address for ",hostname,": ")); if (addresses.len < 16) errint(EHARD,B("no IP address for ",hostname)); byte_copy(localip,16,addresses.s); if (ip6_isv4mapped(localip)) ipv4socket = 1; } s = socket_tcp(); if (s == -1) errint(EHARD,"unable to create socket: "); if (socket_bind_reuse(s,localip,localport,netif) == -1) errint(EHARD,"unable to bind: "); if (!ipv4socket) ipv4socket = ip6_isv4mapped(localip); if (socket_local(s,localip,&localport,&netif) == -1) errint(EHARD,"unable to get local address: "); if (socket_listen(s,backlog) == -1) errint(EHARD,"unable to listen: "); ndelay_off(s); if (gid) if (prot_gid(gid) == -1) errint(EHARD,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) errint(EHARD,"unable to set uid: "); localportstr[fmt_ulong(localportstr,localport)] = 0; if (flag1) { buffer_init(&b,write,1,bspace,sizeof bspace); buffer_puts(&b,localportstr); buffer_puts(&b,"\n"); buffer_flush(&b); } close(0); close(1); printstatus(); for (;;) { while (numchildren >= limit) sig_pause(); sig_unblock(sig_child); t = socket_accept(s,remoteip,&remoteport,&netif); sig_block(sig_child); if (t == -1) continue; ++numchildren; printstatus(); switch(fork()) { case 0: close(s); doit(t); if ((fd_move(0,t) == -1) || (fd_copy(1,0) == -1)) errint(EHARD,"unable to set up descriptors: "); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); pathexec(argv); errint(EHARD,B("unable to run ",*argv,": ")); case -1: errlog(ESOFT,NOTICE,"unable to fork: "); --numchildren; printstatus(); } close(t); } }
unsigned int NAME (char const *prog, char const *const *argv, char const *const *envp, unsigned int uid, unsigned int gid, int *fds) { int p[NPIPES][2] ; int syncpipe[2] ; int pid ; int e ; if (pipe(p[0]) < 0) return 0 ; if (pipe(p[1]) < 0) { e = errno ; goto errp0 ; } #ifdef _CHILD_SPAWN2_ if (pipe(p[2]) < 0) { e = errno ; goto errp1 ; } #endif if (pipe(syncpipe) < 0) { e = errno ; goto errp2 ; } if (coe(syncpipe[1]) < 0) { e = errno ; goto errsp ; } pid = fork() ; if (pid < 0) { e = errno ; goto errsp ; } else if (!pid) { unsigned int m = 25 ; unsigned int n = str_len(PROG) ; char fmt[25 + UINT_FMT] = "SKACLIENT2_ADDITIONAL_FD" ; char name[n + 9] ; byte_copy(name, n, PROG) ; byte_copy(name + n, 9, " (child)") ; PROG = name ; #ifdef _CHILD_SPAWN2_ fmt[m-1] = '=' ; m += uint_fmt(fmt + m, p[2][1]) ; fmt[m++] = 0 ; fd_close(p[2][0]) ; #endif fd_close(syncpipe[0]) ; fd_close(p[1][1]) ; fd_close(p[0][0]) ; if ((fd_move(0, p[1][0]) < 0) || (fd_move(1, p[0][1]) < 0)) goto syncdie ; if (gid && (prot_gid(gid) < 0)) goto syncdie ; if (uid && (prot_uid(uid) < 0)) goto syncdie ; /* XXX: we should unignore signals here, but there's a compromise to be XXX: found between bloat, API complexity, and theoretical correctness. XXX: Not sure what The Right Thing is; just not unignoring atm. XXX: 20130326 edit: The Right Thing is probably to leave the ignore XXX: status alone, because programs that do actual signal handling XXX: are likely to use a selfpipe, and selfpipe_finish() restores XXX: old signal handlers - it knows what to do and we don't. So, XXX: leave that work to selfpipe_finish(). */ sig_blocknone() ; /* empty sigprocmask in the child, always */ pathexec_r_name(prog, argv, envp, env_len(envp), fmt, m) ; syncdie: { char c = errno ; fd_write(syncpipe[1], &c, 1) ; } _exit(111) ; } { char c ; fd_close(syncpipe[1]) ; #ifdef _CHILD_SPAWN2_ fd_close(p[2][1]) ; #endif fd_close(p[1][0]) ; fd_close(p[0][1]) ; p[1][0] = fd_read(syncpipe[0], &c, 1) ; if (p[1][0] < 0) goto killclosewait ; else if (p[1][0]) { e = c ; goto closewait ; } } fd_close(syncpipe[0]) ; if ((ndelay_on(p[0][0]) < 0) || (coe(p[0][0]) < 0) || (ndelay_on(p[1][1]) < 0) || (coe(p[1][1]) < 0)) goto killclosewait ; #ifdef _CHILD_SPAWN2_ if ((ndelay_on(p[2][0]) < 0) || (coe(p[2][0]) < 0)) goto killclosewait ; fds[2] = p[2][0] ; #endif fds[0] = p[0][0] ; fds[1] = p[1][1] ; return (unsigned int)pid ; errsp: fd_close(syncpipe[1]) ; fd_close(syncpipe[0]) ; errp2: #ifdef _CHILD_SPAWN2_ fd_close(p[2][1]) ; fd_close(p[2][0]) ; errp1: #endif fd_close(p[1][1]) ; fd_close(p[1][0]) ; errp0: fd_close(p[0][1]) ; fd_close(p[0][0]) ; errno = e ; return 0 ; killclosewait: e = errno ; kill(pid, SIGKILL) ; closewait: #ifdef _CHILD_SPAWN2_ fd_close(p[2][0]) ; #endif fd_close(p[1][1]) ; fd_close(p[0][0]) ; wait_pid(&syncpipe[1], pid) ; errno = e ; return 0 ; }
int main(int argc, char **argv) { int fdfifo, fdfifowrite; char *x; unsigned long id; VERSIONINFO; x = env_get("WORKDIR"); if (!x) strerr_die2x(111, FATAL, "$WORKDIR not set"); if (chdir(x) == -1) strerr_die4sys(111, FATAL, "unable to chdir to ", x, ": "); x = env_get("GID"); if (!x) strerr_die2x(111, FATAL, "$GID not set"); scan_ulong(x,&id); if (prot_gid((int) id) == -1) strerr_die2sys(111, FATAL, "unable to setgid: "); x = env_get("UID"); if (!x) strerr_die2x(111, FATAL, "$UID not set"); scan_ulong(x,&id); /* undocumented feature */ if(id == 0) if(!env_get("IWANTTORUNASROOTANDKNOWWHATIDO")) strerr_die2x(111, FATAL, "unable to run under uid 0: please change $UID"); if (prot_uid((int) id) == -1) strerr_die2sys(111, FATAL, "unable to setuid: "); buffer_putsflush(buffer_2, ARGV0 "starting\n"); if(fifo_make(FIFONAME, 0620) == -1) strerr_warn4(ARGV0, "unable to create fifo ", FIFONAME, " ", &strerr_sys); fdfifo = open_read(FIFONAME); if(fdfifo == -1) strerr_die4sys(111, FATAL, "unable to open for read ", FIFONAME, " "); coe(fdfifo); ndelay_on(fdfifo); /* DJB says: shouldn't be necessary */ /* we need this to keep the fifo from beeing closed */ fdfifowrite = open_write(FIFONAME); if (fdfifowrite == -1) strerr_die4sys(111, FATAL, "unable to open for write ", FIFONAME, " "); coe(fdfifowrite); /* init a buffer for nonblocking reading */ buffer_init(&wr, waitread, fdfifo, waitreadspace, sizeof waitreadspace); t = dAVLAllocTree(); /* read snapshot of dnsdatatree */ fill_db(); /* SIGALRM can be used to check if dumping the database is needed */ sig_catch(sig_alarm, sigalrm); /* SIGHUP can be used to force dumping the database */ sig_catch(sig_hangup, sighup); /* check if out child is done */ sig_catch(sig_child, sigchld); // XXX SIGINT, SIGTERM, /* do our normal workloop */ doit(); /* we shouldn't get here */ return 1; }