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,": ");
}
Example #2
0
int main(int argc,char **argv)
{
 char *hostname, *x;
 int c, s, t;
 unsigned int u;
 unsigned int cpid = 0;

 opterr = 0;

 while ((c = getopt(argc, argv, "dDoOC:k:c:")) != -1)
  switch (c) {
	case 'c':
	 limit = atoi(optarg);
	 if (limit == 0) usage();
	 break;
	case 'd': flagdelay = 1; break;
	case 'D': flagdelay = 0; break;
	case 'O': flagkillopts = 1; break;
	case 'o': flagkillopts = 0; break;
	case 'C': cacheprogram = 1; break;
	case 'k':
	 autokill = atoi(optarg);
	 if (autokill == 0) usage();
	 break;
	default: abort();
  }
 argc -= optind;
 argv += optind;

 hostname = *argv++;
 if (!hostname) usage();

 x = *argv++;
 if (!x) usage();
 u = 0;
 u = atoi(x);
 if (u != 0) localport = u;
 else usage();

 if (!*argv) usage();

 sig_block(sig_child);
 sig_catch(sig_child,sigchld);
 sig_catch(sig_term,sigterm);
 sig_catch(sig_int,sigint);
 sig_ignore(sig_pipe);

 inet_aton(hostname, (struct in_addr *) &localip);

 if (autokill != 0) pt = ptable_init(limit);

 s = socket_tcp();
 if (s == -1) die(111, "unable to create socket");
 if (socket_bind4_reuse(s,localip,localport) == -1) die(111, "unable to bind");
 if (socket_local4(s,localip,&localport) == -1) die(111, "unable to get local address");
 if (socket_listen(s,20) == -1) die(111, "unable to listen");
 ndelay_off(s);

 fprintf(stderr, "bind: %s:%d\n", hostname, localport);

 close(0);
 close(1);
 printstatus();

 if (cacheprogram) {

   FILE *fp1;
   int fp2;
   char path[1024];
   ssize_t n;

   fp1 = popen(*argv, "r");
   if (fp1 == NULL) {
     fprintf(stderr, "Failed to run command\n");
     exit(1);
   }

   fp2 = open("/var/tmp/tcpd.cache", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
   if (fp2 == -1) {
     fprintf(stderr, "Can't open cache file\n");
     exit(1);
   }

   while ((n = fgets(path, sizeof(path)-1, fp1)) != NULL) {
     if (write(fp2, path, n) == n) {
       fprintf(stderr, "Error occured while creating cache\n");
       exit(1);
     }
   }

   /* close */
   pclose(fp1);
   close(fp2);

   // read cache file into memory
   FILE *f = fopen("/var/tmp/tcpd.cache", "rb");
   fseek(f, 0, SEEK_END);
   cachesize = ftell(f);
   fseek(f, 0, SEEK_SET);  //same as rewind(f);
   cache = malloc(cachesize + 1);
   n = fread(cache, cachesize, 1, f);
   fclose(f);
   cache[cachesize] = 0;
 }

 for (;;) {
   while (numchildren >= limit) {
    if (autokill != 0) ptable_autokill(pt, limit, autokill);
    sig_pause();
   }

   sig_unblock(sig_child);
   t = socket_accept4(s,remoteip,&remoteport);
   sig_block(sig_child);

   if (t == -1) continue;
   ++numchildren; printstatus();
   fprintf(stderr, "inbound connection from %d.%d.%d.%d:%d\n", (unsigned char) remoteip[0], (unsigned char) remoteip[1], (unsigned char) remoteip[2], (unsigned char) remoteip[3], remoteport);

   if (autokill != 0) ptable_autokill(pt,limit,autokill);

   cpid = fork();
   switch(cpid) {
	case 0:
	 close(s);
	 if(flagkillopts) socket_ipoptionskill(t);
	 if(!flagdelay) socket_tcpnodelay(t);
	 if((fd_move(0,t) == -1) || (fd_copy(1,0) == -1)) die(111,"unable to setup descriptors");
	 sig_uncatch(sig_child);
	 sig_unblock(sig_child);
	 sig_uncatch(sig_term);
	 sig_uncatch(sig_int);
	 sig_uncatch(sig_pipe);

	 if (cacheprogram) {
	   printf("%s", cache);
	   close(t);
	   exit(0);
	 } else {
	   if(execve(*argv,argv,NULL) == 0) {
	     close(t);
	     exit(0);
	   } else {
	     die(111, "unable to run argv");
	   }
	 }
	 break;
	case -1:
	 // unable to fork
	 eprint(P_WARN,"unable to fork");
	 --numchildren; printstatus();
	 break;
	default:
	 fprintf(stderr, "fork: child pid %d\n", cpid);
	 if (autokill != 0) ptable_set(pt, limit, cpid, time(NULL));
	 break;
   }
   close(t);
 }
}
Example #3
0
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,": ");
}
Example #4
0
void doit(int t)
{
  int j;
  uint32 scope_id;

  if (ip6_isv4mapped(remoteip))
    remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0;
  else
    remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0;

  if (verbosity >= 2) {
    strnum[fmt_ulong(strnum,getpid())] = 0;
    log(B("pid ",strnum," from ",remoteipstr,0));
  }

  if (flagkillopts)
    socket_ipoptionskill(t);
  if (!flagdelay)
    socket_tcpnodelay(t);

  if (*banner) {
    buffer_init(&b,write,t,bspace,sizeof bspace);
    if (buffer_putsflush(&b,banner) == -1)
      errint(EHARD,"unable to print banner: ");
  }

  if (socket_local(t,localip,&localport,&scope_id) == -1)
    errint(EHARD,"unable to get local address: ");

  if (ip6_isv4mapped(localip))
    localipstr[ip4_fmt(localipstr,localip+12)] = 0;
  else
    localipstr[ip6_fmt(localipstr,localip)] = 0;
  remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0;

  if (!localhost)
    if (dns_name(&localhostsa,localip) == 0)
      if (localhostsa.len) {
    if (!stralloc_0(&localhostsa)) errmem;
    localhost = localhostsa.s;
      }
  env("PROTO","TCP");

  env("TCPLOCALIP",localipstr);
  env("TCPLOCALPORT",localportstr);
  env("TCPLOCALHOST",localhost);

  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 (!flagparanoid) {
      if (!stralloc_0(&remotehostsa)) errmem;
      remotehost = remotehostsa.s;
    }
      }
  env("TCPREMOTEIP",remoteipstr);
  env("TCPREMOTEPORT",remoteportstr);
  env("TCPREMOTEHOST",remotehost);

  if (flagremoteinfo) {
    if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1)
      flagremoteinfo = 0;
    if (!stralloc_0(&tcpremoteinfo)) errmem;
  }
  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 {
      char* temp;
	  if (ip6_isv4mapped(remoteip))
        temp=remoteipstr+7;
      else
        temp=remoteipstr;
      if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules();
      close(fdrules);
//      log(B("checking tcp rules for ",remotehost,": pass"));
    }
  }

  if (verbosity >= 2) {
    strnum[fmt_ulong(strnum,getpid())] = 0;
    if (!stralloc_copys(&tmp,"qmail-tcpsrv: ")) errmem;
    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(":<remote info>"); if (flagremoteinfo) safecats(tcpremoteinfo.s);
    cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s);
    cats(":"); safecats(remoteportstr);
    cats("\n");
    buffer_putflush(buffer_2,tmp.s,tmp.len);
  }

  if (flagdeny) _exit(100);
}