Esempio n. 1
0
int SP_MatrixsslChannelFactory :: init( const char * certFile, const char * keyFile )
{
	if( matrixSslOpen() < 0 ) {
		sp_syslog( LOG_WARNING, "matrixSslOpen failed" );
	}

	if( matrixSslReadKeys( &mKeys, certFile, keyFile, NULL, NULL ) < 0 ) {
		sp_syslog( LOG_WARNING, "Error reading or parsing %s or %s.", certFile, keyFile );
	}

	return 0;
}
Esempio n. 2
0
int
openssl_env_init(openssl_env *env, char *engine, int server) {

  if (!_options.sslcertfile || !_options.sslkeyfile) {
    syslog(LOG_ERR, "options sslcertfile and sslkeyfile are required");
    return 0;
  }

#ifdef HAVE_OPENSSL
  {
    int err = _openssl_env_init(env, engine, server);

    if (_options.sslkeypass) {
      SSL_CTX_set_default_passwd_cb(env->ctx, _openssl_passwd);
    }

    if (!openssl_use_certificate(env, _options.sslcertfile) ||
	!openssl_use_privatekey(env, _options.sslkeyfile)) {
      syslog(LOG_ERR, "failed reading setup sslcertfile and/or sslkeyfile");
      return 0;
    }

    if (_options.sslcafile) {
      if (!openssl_cacert_location(env, _options.sslcafile, 0)) {
	syslog(LOG_ERR, "failed reading sslcafile");
	return 0;
      }
    }

    env->ready = 1;
    return err;
  }
#else
  syslog(LOG_DEBUG, "%s(%d): MatrixSSL Setup:", __FUNCTION__, __LINE__);
  syslog(LOG_DEBUG, "%s(%d): SSL cert: %s", __FUNCTION__, __LINE__, _options.sslcertfile);
  syslog(LOG_DEBUG, "%s(%d): SSL key: %s", __FUNCTION__, __LINE__, _options.sslkeyfile);
  syslog(LOG_DEBUG, "%s(%d): SSL pass: %s", __FUNCTION__, __LINE__, _options.sslkeypass?_options.sslkeypass:"******");
  syslog(LOG_DEBUG, "%s(%d): SSL ca: %s", __FUNCTION__, __LINE__, _options.sslcafile?_options.sslcafile:"null");
  if ( matrixSslReadKeys( &env->keys,
			  _options.sslcertfile,
			  _options.sslkeyfile,
			  _options.sslkeypass,
			  _options.sslcafile ) < 0 ) {
    syslog(LOG_ERR, "%s: could not load ssl certificate or and/or key file", strerror(errno));
    return 0;
  }

  env->ready = 1;
  return 1;
#endif
}
Esempio n. 3
0
int main(int argc, char **argv)
#endif
{
	sslConn_t		*cp;
	sslKeys_t		*keys;
	SOCKET			listenfd, fd;
	WSADATA			wsaData;
	unsigned char	buf[1024];
	unsigned char	*response, *c;
	int				responseHdrLen, acceptAgain, flags;
	int				bytes, status, quit, again, rc, err;
#if USE_MEM_CERTS
	unsigned char	*servBin, *servKeyBin, *caBin; 
	int				servBinLen, caBinLen, servKeyBinLen;
#endif

	cp = NULL;
/*
	Initialize Windows sockets (no-op on other platforms)
*/
	WSAStartup(MAKEWORD(1,1), &wsaData);
/*
	Initialize the MatrixSSL Library, and read in the public key (certificate)
	and private key.
*/
	if (matrixSslOpen() < 0) {
		fprintf(stderr, "matrixSslOpen failed, exiting...");
	}

#if USE_MEM_CERTS
/*
	Example of DER binary certs for matrixSslReadKeysMem
*/
	getFileBin("certSrv.der", &servBin, &servBinLen);
	getFileBin("privkeySrv.der", &servKeyBin, &servKeyBinLen);
	getFileBin("CACertCln.der", &caBin, &caBinLen);

	matrixSslReadKeysMem(&keys, servBin, servBinLen,
		servKeyBin, servKeyBinLen, caBin, caBinLen); 

	free(servBin);
	free(servKeyBin);
	free(caBin);
#else 
/*
	Standard PEM files
*/
	if (matrixSslReadKeys(&keys, certfile, keyfile, NULL, NULL) < 0)  {
		fprintf(stderr, "Error reading or parsing %s or %s.\n", 
			certfile, keyfile);
		goto promptAndExit;
	}
#endif /* USE_MEM_CERTS */
	fprintf(stdout, 
		"Run httpsClient or type https://127.0.0.1:%d into your local Web browser.\n",
		HTTPS_PORT);
/*
	Create the listen socket
*/
	if ((listenfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
		fprintf(stderr, "Cannot listen on port %d\n", HTTPS_PORT);
		goto promptAndExit;
	}
/*
	Set blocking or not on the listen socket
*/
	setSocketBlock(listenfd);
/*
	Loop control initalization
*/
	quit = 0;
	again = 0;
	flags = 0;

	acceptAgain = 1;
/*
	Main connection loop
*/
	while (!quit) {

		if (acceptAgain) {
/*
			sslAccept creates a new server session
*/
			/* TODO - deadlock on blocking socket accept.  Should disable blocking here */
			if ((fd = socketAccept(listenfd, &err)) == INVALID_SOCKET) {
				fprintf(stdout, "Error accepting connection: %d\n", err);
				continue;
			}
			if ((rc = sslAccept(&cp, fd, keys, NULL, flags)) != 0) {
				socketShutdown(fd);
				continue;
			}

			flags = 0;
			acceptAgain = 0;
		}
/*
		Read response
		< 0 return indicates an error.
		0 return indicates an EOF or CLOSE_NOTIFY in this situation
		> 0 indicates that some bytes were read.  Keep reading until we see
		the /r/n/r/n from the GET request.  We don't actually parse the request,
		we just echo it back.
*/
		c = buf;
readMore:
		if ((rc = sslRead(cp, c, sizeof(buf) - (int)(c - buf), &status)) > 0) {
			c += rc;
			if (c - buf < 4 || memcmp(c - 4, "\r\n\r\n", 4) != 0) {
				goto readMore;
			}
		} else {
			if (rc < 0) {
				fprintf(stdout, "sslRead error.  dropping connection.\n");
			}
			if (rc < 0 || status == SSLSOCKET_EOF ||
					status == SSLSOCKET_CLOSE_NOTIFY) {
				socketShutdown(cp->fd);
				sslFreeConnection(&cp);
				acceptAgain = 1;
				continue;
			}
			goto readMore;
		}
/*
		Done reading.  If the incoming data starts with the quitString,
		quit the application after this request
*/
		if (memcmp(buf, quitString, min(c - buf, 
				(int)strlen(quitString))) == 0) {
			quit++;
			fprintf(stdout, "Q");
		}
/*
		If the incoming data starts with the againString,
		we are getting a pipeline request on the same session.  Don't
		close and wait for new connection in this case.
*/
		if (memcmp(buf, againString,
				min(c - buf, (int)strlen(againString))) == 0) {
			again++;
			fprintf(stdout, "A");
		} else {
			fprintf(stdout, "R");
			again = 0;
		}
/*
		Copy the canned response header and decoded data from socket as the
		response (reflector)
*/
		responseHdrLen = (int)strlen(responseHdr);
		bytes = responseHdrLen + (int)(c - buf);
		response = malloc(bytes);
		memcpy(response, responseHdr, responseHdrLen);
		memcpy(response + responseHdrLen, buf, c - buf); 
/*
		Send response.
		< 0 return indicates an error.
		0 return indicates not all data was sent and we must retry
		> 0 indicates that all requested bytes were sent
*/
writeMore:
		rc = sslWrite(cp, response, bytes, &status);
		if (rc < 0) {
			free(response);
			fprintf(stdout, "Internal sslWrite error\n");
			socketShutdown(cp->fd);
			sslFreeConnection(&cp);
			continue;
		} else if (rc == 0) {
			goto writeMore;
		}
		free(response);
/*
		If we saw an /again request, loop up and process another pipelined
		HTTP request.  The /again request is supported in the httpsClient
		example code.
*/
		if (again) {
			continue;
		}
/*
		Send a closure alert for clean shutdown of remote SSL connection
		This is for good form, some implementations just close the socket
*/
		sslWriteClosureAlert(cp);
/*
		Close the socket and wait for next connection (new session)
*/
		socketShutdown(cp->fd);
		sslFreeConnection(&cp);
		acceptAgain = 1;
	}
/*
	Close listening socket, free remaining items
*/
	if (cp && cp->ssl) {
		socketShutdown(cp->fd);
		sslFreeConnection(&cp);
	}
	socketShutdown(listenfd);

	matrixSslFreeKeys(keys);
	matrixSslClose();
	WSACleanup();
promptAndExit:
	fprintf(stdout, "\n\nPress return to exit...\n");
	getchar();
	return 0;
}
Esempio n. 4
0
int main(int argc, char **argv)
#endif
{
	SOCKET			srv_fd;
	int				status;
	WSADATA			wsaData;
	
	// options
	char				*srv_host = NULL;
	int				srv_port = 0;
	char 				*keyfile = NULL; //"privkeySrv.pem";
	char 				*certfile = NULL; //"certSrv.pem";
	int				vlevel = 0;
	char 				*cpos,*opos;
	int tmpport;
	int c;
	int 			intarg;
 	
#if VXWORKS
	int					argc;
	char				**argv;
	parseCmdLineArgs(arg1, &argc, &argv);
#endif /* VXWORKS */

#if WINCE
	int					argc;
	char				**argv;
	char				args[256];

/*
 *	parseCmdLineArgs expects an ASCII string and CE is unicoded, so convert
 *	the command line.  args will get hacked up, so you can't pass in a
 *	static string.
 */
	WideCharToMultiByte(CP_ACP, 0, lpCmdLine, -1, args, 256, NULL, NULL);

/*
 *	Parse the command line into an argv array.  This allocs memory, so
 *	we have to free argv when we're done.
 */
	parseCmdLineArgs(args, &argc, &argv);
#endif /* WINCE */


/*
	prepare
*/
	
#ifndef USE_FORK
	memset(connections,0,MAXPROXYCOUNT*sizeof(struct proxyConnection));
#endif
	
/*
	getopt
*/
	/* Gemtek add +++ */
	if(argc == 1) usage(1);
	/* Gemtek add --- */
	
	for (;;) {
		c = getopt (argc, argv, "VD:P:fo:cd:r:p:A:v:h");
		if (c == -1) {
			break;
		}

		switch (c) {
			case 'c':
				// client mode
				isClient=1;
				break;
			
			case 'd':
				// daemon mode [host:]port
				cpos = NULL;
				tmpport = 0;
				if((cpos = strchr(optarg,':'))) {				
					*cpos = '\0';
					if(optarg && optarg[0])
						srv_host = optarg;
					optarg = ++cpos;
				}
				if(optarg && optarg[0]) {
					tmpport = (int)strtol(optarg, (char **)NULL, 0);
					if(tmpport) srv_port = tmpport;
				}
				break;
			
			case 'r':
				// remote [host:]port
				cpos = NULL;
				tmpport = 0;
				if((cpos = strchr(optarg,':'))) {				
					*cpos = '\0';
					if(optarg && optarg[0])
						dst_host = optarg;
					optarg = ++cpos;
				}
				if(optarg && optarg[0]) {
					tmpport = (int)strtol(optarg, (char **)NULL, 0);
					if(tmpport) dst_port = tmpport;
				}
				break;
				
			case 'p':
				// pemfile (requred in servermode)
				keyfile = optarg;
				break;
			
			case 'A':
				// CA file
				certfile = optarg;
				break;
			
			case 'v':
				// veryfication level
				if(optarg && optarg[0]) {
					vlevel = (int)strtol(optarg, (char **)NULL, 0);
					if(vlevel == 1 ) {
						cervalidator = certChecker;
					}
					else if(vlevel > 3 || vlevel < 0) {
						fprintf(stderr,"-v takes whole numbers between 0 and 3");
						exit(2);
					}
				}
				break;
			
			case 'P':
				// create a pidfile
				pidfile=optarg;
				break;
				
			case 'f':
				// run in foreground.
				nofork=1;
				nosysl=1;
				break;
				
			case 'o':
				// append logmessages to a file instead of stdout/syslog
				break;
				
			case 'O':
				// socket options. TODO
				break;
			
			case 'D':
				// debug level 0...7
				intarg=strtol(optarg,NULL,0);
				if(intarg<0 || intarg>7) {
					usage(1);
				}
				gLogLevel=intarg;
				break;
				
			case 'V':
				// version
				break;
				
			case '?':
			case 'h':
				usage(0);
				break;
			
			default:
				usage(1);
				break;
		}
	}


/* install handlers */
	signal( SIGPIPE, SIG_IGN );
	signal(SIGCHLD,sigchld_handler); /* ignore child */
	signal(SIGHUP,kill_handler); /* catch hangup signal */
	signal(SIGTERM,kill_handler); /* catch kill signal */
	
/*
	Initialize Windows sockets (no-op on other platforms)
*/
	WSAStartup(MAKEWORD(1,1), &wsaData);
	
	if(!nosysl) {
		openlog("matrixtunnel", LOG_PID, LOG_DAEMON);
		setlogmask(LOG_UPTO(gLogLevel));
	}
	
/*
	Initialize the MatrixSSL Library, and read in the public key (certificate)
	and private key.
*/
	if (matrixSslOpen() < 0) {
		ELOG("matrixSslOpen failed, exiting...");
		exit(1);
	}

/*
	Standard PEM files
*/
	if (matrixSslReadKeys(&keys, certfile, keyfile, NULL, NULL) < 0)  {
		ELOG("Error reading or parsing %s or %s, exiting...", 
			certfile, keyfile);
		exit(1);
	}

	// go to background
	if(!nofork) {
		daemonize();
	}

/*
	Create the listen socket
*/
	if ((srv_fd = socketListen(srv_port, &status)) == INVALID_SOCKET) {
		ELOG("Cannot listen on port %d, exiting...", srv_port);
		exit(1);
	}
/*
	Set blocking or not on the listen socket
*/
	setSocketBlock(srv_fd);

/*
	Main connection loop
*/
	struct proxyConnection	*cp=NULL;
	struct proxyConnection	*ncp;
	
	fd_set	rs, ws, es, cr;
	int			fdmax;
	struct timeval tv;
	int			res, dontClose;
	
	char		buf[4096];
	int pc, sc;
	
	int			ccount;
	
	while (!quit) {
		fdmax=srv_fd;
		ncp=NULL;
		
		FD_ZERO(&rs);
		FD_ZERO(&ws);
		FD_ZERO(&es);
		
		FD_SET(srv_fd,&rs);
		FD_SET(srv_fd,&ws);
		FD_SET(srv_fd,&es);
		ccount=0;
		
#ifndef USE_FORK
		DLOG("next select on fds: %d ",srv_fd);
		for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
			if (cp->done) {
				closeProxyConnection(cp);
			}
			if (cp->secure_up) {
				FD_SET(cp->secure->fd,&rs);
				FD_SET(cp->secure->fd,&ws);
				FD_SET(cp->secure->fd,&es);

				if (fdmax < cp->secure->fd)
					fdmax = cp->secure->fd;
				
				DLOG("fd: %d",cp->secure->fd);
				ccount++;
			}
			if (cp->plain_up) {
				FD_SET(cp->plain,&rs);			
				FD_SET(cp->plain,&ws);
				FD_SET(cp->plain,&es);
					
				if (fdmax < cp->plain)
					fdmax = cp->plain;
				
				DLOG("fd: %d",cp->plain);
				ccount++;
			}
			if(!ncp && !cp->inuse){
				ncp=cp;
				memset(ncp,0,sizeof(struct proxyConnection));
			}
		}
#else
		struct proxyConnection	ncp_s;
		ncp=&ncp_s;
		memset(ncp,0,sizeof(struct proxyConnection));
#endif
		
		tv.tv_sec=10;
		tv.tv_usec=0;

		DLOG("main : select on %d open connections. fdmax: %d", ccount, fdmax);
		res=select(fdmax+1,&rs,NULL,&es,&tv);
		DLOG("select returned: %d %s", res , strerror(errno) );

		if(res<0) {
			perror("select");
			continue;
		}
		
		if(res==0)
			continue;

#ifndef USE_FORK
		// handle open connections
		for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
			if (cp->secure_up && cp->plain_up) {
				if(FD_ISSET(cp->secure->fd,&es) || FD_ISSET(cp->plain,&es)) {
						closeProxyConnection(cp);
						continue;
				}
				
				if(secureReady(cp)) {
					sc=proxyReadwrite(cp,1);
					if(sc<0) {
						closeProxyConnection(cp);
						continue;
					}
				}
				
				if(plainReady(cp)) {
					pc=proxyReadwrite(cp,0);
					if(pc<0) {
						closeProxyConnection(cp);
						continue;
					}
				}
			}
		}
#endif

		// do we have new connections?
		if(FD_ISSET(srv_fd,&rs)) {
			proxyAccept(srv_fd,ncp);
		}			
	}

/*
	Close listening socket, free remaining items
*/
	socketShutdown(srv_fd);
	
#ifndef USE_FORK
	for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
		closeProxyConnection(cp);
	}
#endif
	
	if(!nosysl) {
		closelog();
	}
	
	matrixSslFreeKeys(keys);
	matrixSslClose();
	WSACleanup();
	return 0;
}
Esempio n. 5
0
int main(int argc, char **argv) {
  int opt;
  char *user =0;
  char *host;
  unsigned long port;
  int pid;
  int s;
  int conn;
  int delim;

  progname =*argv;
  phccmax =0;

#ifdef SSLSVD
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vVU:/:Z:K:")) != opteof) {
#else
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vV")) != opteof) {
#endif
    switch(opt) {
    case 'c': scan_ulong(optarg, &cmax); if (cmax < 1) usage(); break;
    case 'C':
      delim =scan_ulong(optarg, &phccmax);
      if (phccmax < 1) usage();
      if (optarg[delim] == ':') {
        if (ipsvd_fmt_msg(&msg, optarg +delim +1) == -1) die_nomem();
        if (! stralloc_0(&msg)) die_nomem();
        phccmsg =msg.s;
      }
      break;
    case 'i': if (instructs) usage(); instructs =optarg; break;
    case 'x': if (instructs) usage(); instructs =optarg; iscdb =1; break;
    case 'u': user =(char*)optarg; break;
    case 'l':
      if (! stralloc_copys(&local_hostname, optarg)) die_nomem();
      if (! stralloc_0(&local_hostname)) die_nomem();
      break;
    case 'E': ucspi =0; break;
    case 'b': scan_ulong(optarg, &backlog); break;
    case 'h': lookuphost =1; break;
    case 'p': lookuphost =1; paranoid =1; break;
    case 't': scan_ulong(optarg, &timeout); break;
    case 'v': ++verbose; break;
#ifdef SSLSVD
    case 'U': ssluser =(char*)optarg; break;
    case '/': root =(char*)optarg; break;
    case 'Z': cert =(char*)optarg; break;
    case 'K': key =(char*)optarg; break;
#endif
    case 'V': strerr_warn1(VERSION, 0);
    case '?': usage();
    }
  }
  argv +=optind;

  if (! argv || ! *argv) usage();
  host =*argv++;
  if (! argv || ! *argv) usage();
  local_port =*argv++;
  if (! argv || ! *argv) usage();
  prog =(const char **)argv;
  if (phccmax > cmax) phccmax =cmax;

  if (user)
    if (! uidgids_get(&ugid, user)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", user, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", user);
    }
#ifdef SSLSVD
  svuser =user;
  client =0;
  if ((getuid() == 0) && (! ssluser))
    strerr_die2x(100, FATAL, "-U ssluser must be set when running as root");
  if (ssluser)
    if (! uidgids_get(&sslugid, ssluser)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", ssluser, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", ssluser);
    }
  if (! cert) cert ="./cert.pem";
  if (! key) key =cert;
  if (matrixSslOpen() < 0) fatal("unable to initialize ssl");
  if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
    if (client) fatal("unable to read cert, key, or ca file");
    fatal("unable to read cert or key file");
  }
  if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
    strerr_die2x(111, FATAL, "unable to create ssl session");
#endif

  dns_random_init(seed);
  sig_block(sig_child);
  sig_catch(sig_child, sig_child_handler);
  sig_catch(sig_term, sig_term_handler);
  sig_ignore(sig_pipe);

  if (phccmax) if (ipsvd_phcc_init(cmax) == -1) die_nomem();

  if (str_equal(host, "")) host ="0.0.0.0";
  if (str_equal(host, "0")) host ="0.0.0.0";

  if (! ipsvd_scan_port(local_port, "tcp", &port))
    strerr_die3x(100, FATAL, "unknown port number or name: ", local_port);

  if (! stralloc_copys(&sa, host)) die_nomem();
  if ((dns_ip4(&ips, &sa) == -1) || (ips.len < 4))
    if (dns_ip4_qualify(&ips, &fqdn, &sa) == -1)
      fatal2("unable to look up ip address", host);
  if (ips.len < 4)
    strerr_die3x(100, FATAL, "unable to look up ip address: ", host);
  ips.len =4;
  if (! stralloc_0(&ips)) die_nomem();
  local_ip[ipsvd_fmt_ip(local_ip, ips.s)] =0;

  if (! lookuphost) {
    if (! stralloc_copys(&remote_hostname, "")) die_nomem();
    if (! stralloc_0(&remote_hostname)) die_nomem();
  }

  if ((s =socket_tcp()) == -1) fatal("unable to create socket");
  if (socket_bind4_reuse(s, ips.s, port) == -1)
    fatal("unable to bind socket");
  if (listen(s, backlog) == -1) fatal("unable to listen");
  ndelay_off(s);

#ifdef SSLSVD
#else
  if (user) {
    /* drop permissions */
    if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to set groups");
    if (setgid(*ugid.gid) == -1) fatal("unable to set gid");
    if (prot_uid(ugid.uid) == -1) fatal("unable to set uid");
  }
#endif
  close(0);

  if (verbose) {
    out(INFO); out("listening on "); outfix(local_ip); out(":");
    outfix(local_port);
#ifdef SSLSVD
#else
    if (user) {
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.uid)] =0;
      out(", uid "); out(bufnum);
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.gid)] =0;
      out(", gid "); out(bufnum);
    }
#endif
    flush(", starting.\n");
  }
  for (;;) {
    while (cnum >= cmax) sig_pause();
    socka_size =sizeof(socka);

    sig_unblock(sig_child);
    conn =accept(s, (struct sockaddr *)&socka, &socka_size);
    sig_block(sig_child);

    if (conn == -1) {
      if (errno != error_intr) warn("unable to accept connection");
      continue;
    }
    cnum++;

    if (verbose) connection_status();
    if (phccmax) phcc =ipsvd_phcc_add((char*)&socka.sin_addr);
    if ((pid =fork()) == -1) {
      warn2("drop connection", "unable to fork");
      close(conn);
      continue;
    }
    if (pid == 0) {
      /* child */
      close(s);
#ifdef SSLSVD
      if (*progname) *progname ='\\';
#endif
      connection_accept(conn);
    }
    if (phccmax) ipsvd_phcc_setpid(pid);
    close(conn);
  }
  _exit(0);
}
Esempio n. 6
0
int tcpudpsvd_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
	char *str_C, *str_t;
	char *user;
	struct hcc *hccp;
	const char *instructs;
	char *msg_per_host = NULL;
	unsigned len_per_host = len_per_host; /* gcc */
#ifndef SSLSVD
	struct bb_uidgid_t ugid;
#endif
	bool tcp;
	uint16_t local_port;
	char *preset_local_hostname = NULL;
	char *remote_hostname = remote_hostname; /* for compiler */
	char *remote_addr = remote_addr; /* for compiler */
	len_and_sockaddr *lsa;
	len_and_sockaddr local, remote;
	socklen_t sa_len;
	int pid;
	int sock;
	int conn;
	unsigned backlog = 20;

	INIT_G();

	tcp = (applet_name[0] == 't');

	/* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */
	opt_complementary = "-3:i--i:ph:vv:b+:c+";
#ifdef SSLSVD
	getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
		&cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
		&backlog, &str_t, &ssluser, &root, &cert, &key, &verbose
	);
#else
	/* "+": stop on first non-option */
	getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v",
		&cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
		&backlog, &str_t, &verbose
	);
#endif
	if (option_mask32 & OPT_C) { /* -C n[:message] */
		max_per_host = bb_strtou(str_C, &str_C, 10);
		if (str_C[0]) {
			if (str_C[0] != ':')
				bb_show_usage();
			msg_per_host = str_C + 1;
			len_per_host = strlen(msg_per_host);
		}
	}
	if (max_per_host > cmax)
		max_per_host = cmax;
	if (option_mask32 & OPT_u) {
		if (!get_uidgid(&ugid, user, 1))
			bb_error_msg_and_die("unknown user/group: %s", user);
	}
#ifdef SSLSVD
	if (option_mask32 & OPT_U) ssluser = optarg;
	if (option_mask32 & OPT_slash) root = optarg;
	if (option_mask32 & OPT_Z) cert = optarg;
	if (option_mask32 & OPT_K) key = optarg;
#endif
	argv += optind;
	if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
		argv[0] = (char*)"0.0.0.0";

	/* Per-IP flood protection is not thought-out for UDP */
	if (!tcp)
		max_per_host = 0;

	bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */

#ifdef SSLSVD
	sslser = user;
	client = 0;
	if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
		xfunc_exitcode = 100;
		bb_error_msg_and_die("-U ssluser must be set when running as root");
	}
	if (option_mask32 & OPT_u)
		if (!uidgid_get(&sslugid, ssluser, 1)) {
			if (errno) {
				bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
			}
			bb_error_msg_and_die("unknown user/group '%s'", ssluser);
		}
	if (!cert) cert = "./cert.pem";
	if (!key) key = cert;
	if (matrixSslOpen() < 0)
		fatal("cannot initialize ssl");
	if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
		if (client)
			fatal("cannot read cert, key, or ca file");
		fatal("cannot read cert or key file");
	}
	if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
		fatal("cannot create ssl session");
#endif

	sig_block(SIGCHLD);
	signal(SIGCHLD, sig_child_handler);
	bb_signals(BB_FATAL_SIGS, sig_term_handler);
	signal(SIGPIPE, SIG_IGN);

	if (max_per_host)
		ipsvd_perhost_init(cmax);

	local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
	lsa = xhost2sockaddr(argv[0], local_port);
	argv += 2;

	sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
	setsockopt_reuseaddr(sock);
	sa_len = lsa->len; /* I presume sockaddr len stays the same */
	xbind(sock, &lsa->u.sa, sa_len);
	if (tcp)
		xlisten(sock, backlog);
	else /* udp: needed for recv_from_to to work: */
		socket_want_pktinfo(sock);
	/* ndelay_off(sock); - it is the default I think? */

#ifndef SSLSVD
	if (option_mask32 & OPT_u) {
		/* drop permissions */
		xsetgid(ugid.gid);
		xsetuid(ugid.uid);
	}
#endif

	if (verbose) {
		char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa);
		bb_error_msg("listening on %s, starting", addr);
		free(addr);
#ifndef SSLSVD
		if (option_mask32 & OPT_u)
			printf(", uid %u, gid %u",
				(unsigned)ugid.uid, (unsigned)ugid.gid);
#endif
	}

	/* Main accept() loop */

 again:
	hccp = NULL;

	while (cnum >= cmax)
		wait_for_any_sig(); /* expecting SIGCHLD */

	/* Accept a connection to fd #0 */
 again1:
	close(0);
 again2:
	sig_unblock(SIGCHLD);
	local.len = remote.len = sa_len;
	if (tcp) {
		conn = accept(sock, &remote.u.sa, &remote.len);
	} else {
		/* In case recv_from_to won't be able to recover local addr.
		 * Also sets port - recv_from_to is unable to do it. */
		local = *lsa;
		conn = recv_from_to(sock, NULL, 0, MSG_PEEK,
				&remote.u.sa, &local.u.sa, sa_len);
	}
	sig_block(SIGCHLD);
	if (conn < 0) {
		if (errno != EINTR)
			bb_perror_msg(tcp ? "accept" : "recv");
		goto again2;
	}
	xmove_fd(tcp ? conn : sock, 0);

	if (max_per_host) {
		/* Drop connection immediately if cur_per_host > max_per_host
		 * (minimizing load under SYN flood) */
		remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa);
		cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp);
		if (cur_per_host > max_per_host) {
			/* ipsvd_perhost_add detected that max is exceeded
			 * (and did not store ip in connection table) */
			free(remote_addr);
			if (msg_per_host) {
				/* don't block or test for errors */
				send(0, msg_per_host, len_per_host, MSG_DONTWAIT);
			}
			goto again1;
		}
		/* NB: remote_addr is not leaked, it is stored in conn table */
	}

	if (!tcp) {
		/* Voodoo magic: making udp sockets each receive its own
		 * packets is not trivial, and I still not sure
		 * I do it 100% right.
		 * 1) we have to do it before fork()
		 * 2) order is important - is it right now? */

		/* Open new non-connected UDP socket for further clients... */
		sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
		setsockopt_reuseaddr(sock);
		/* Make plain write/send work for old socket by supplying default
		 * destination address. This also restricts incoming packets
		 * to ones coming from this remote IP. */
		xconnect(0, &remote.u.sa, sa_len);
	/* hole? at this point we have no wildcard udp socket...
	 * can this cause clients to get "port unreachable" icmp?
	 * Yup, time window is very small, but it exists (is it?) */
		/* ..."open new socket", continued */
		xbind(sock, &lsa->u.sa, sa_len);
		socket_want_pktinfo(sock);

		/* Doesn't work:
		 * we cannot replace fd #0 - we will lose pending packet
		 * which is already buffered for us! And we cannot use fd #1
		 * instead - it will "intercept" all following packets, but child
		 * does not expect data coming *from fd #1*! */
#if 0
		/* Make it so that local addr is fixed to localp->u.sa
		 * and we don't accidentally accept packets to other local IPs. */
		/* NB: we possibly bind to the _very_ same_ address & port as the one
		 * already bound in parent! This seems to work in Linux.
		 * (otherwise we can move socket to fd #0 only if bind succeeds) */
		close(0);
		set_nport(localp, htons(local_port));
		xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0);
		setsockopt_reuseaddr(0); /* crucial */
		xbind(0, &localp->u.sa, localp->len);
#endif
	}

	pid = vfork();
	if (pid == -1) {
		bb_perror_msg("vfork");
		goto again;
	}

	if (pid != 0) {
		/* Parent */
		cnum++;
		if (verbose)
			connection_status();
		if (hccp)
			hccp->pid = pid;
		/* clean up changes done by vforked child */
		undo_xsetenv();
		goto again;
	}

	/* Child: prepare env, log, and exec prog */

	/* Closing tcp listening socket */
	if (tcp)
		close(sock);

	{ /* vfork alert! every xmalloc in this block should be freed! */
		char *local_hostname = local_hostname; /* for compiler */
		char *local_addr = NULL;
		char *free_me0 = NULL;
		char *free_me1 = NULL;
		char *free_me2 = NULL;

		if (verbose || !(option_mask32 & OPT_E)) {
			if (!max_per_host) /* remote_addr is not yet known */
				free_me0 = remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa);
			if (option_mask32 & OPT_h) {
				free_me1 = remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa);
				if (!remote_hostname) {
					bb_error_msg("cannot look up hostname for %s", remote_addr);
					remote_hostname = remote_addr;
				}
			}
			/* Find out local IP peer connected to.
			 * Errors ignored (I'm not paranoid enough to imagine kernel
			 * which doesn't know local IP). */
			if (tcp)
				getsockname(0, &local.u.sa, &local.len);
			/* else: for UDP it is done earlier by parent */
			local_addr = xmalloc_sockaddr2dotted(&local.u.sa);
			if (option_mask32 & OPT_h) {
				local_hostname = preset_local_hostname;
				if (!local_hostname) {
					free_me2 = local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa);
					if (!local_hostname)
						bb_error_msg_and_die("cannot look up hostname for %s", local_addr);
				}
				/* else: local_hostname is not NULL, but is NOT malloced! */
			}
		}
		if (verbose) {
			pid = getpid();
			if (max_per_host) {
				bb_error_msg("concurrency %s %u/%u",
					remote_addr,
					cur_per_host, max_per_host);
			}
			bb_error_msg((option_mask32 & OPT_h)
				? "start %u %s-%s (%s-%s)"
				: "start %u %s-%s",
				pid,
				local_addr, remote_addr,
				local_hostname, remote_hostname);
		}

		if (!(option_mask32 & OPT_E)) {
			/* setup ucspi env */
			const char *proto = tcp ? "TCP" : "UDP";

			/* Extract "original" destination addr:port
			 * from Linux firewall. Useful when you redirect
			 * an outbond connection to local handler, and it needs
			 * to know where it originally tried to connect */
			if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &local.u.sa, &local.len) == 0) {
				char *addr = xmalloc_sockaddr2dotted(&local.u.sa);
				xsetenv_plain("TCPORIGDSTADDR", addr);
				free(addr);
			}
			xsetenv_plain("PROTO", proto);
			xsetenv_proto(proto, "LOCALADDR", local_addr);
			xsetenv_proto(proto, "REMOTEADDR", remote_addr);
			if (option_mask32 & OPT_h) {
				xsetenv_proto(proto, "LOCALHOST", local_hostname);
				xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
			}
			//compat? xsetenv_proto(proto, "REMOTEINFO", "");
			/* additional */
			if (cur_per_host > 0) /* can not be true for udp */
				xsetenv_plain("TCPCONCURRENCY", utoa(cur_per_host));
		}
		free(local_addr);
		free(free_me0);
		free(free_me1);
		free(free_me2);
	}

	xdup2(0, 1);

	signal(SIGTERM, SIG_DFL);
	signal(SIGPIPE, SIG_DFL);
	signal(SIGCHLD, SIG_DFL);
	sig_unblock(SIGCHLD);

#ifdef SSLSVD
	strcpy(id, utoa(pid));
	ssl_io(0, argv);
#else
	BB_EXECVP(argv[0], argv);
#endif
	bb_perror_msg_and_die("exec '%s'", argv[0]);
}
Esempio n. 7
0
int ssl_io(unsigned int newsession, const char **prog) {
  if (client) { fdstdin =6; fdstdou =7; }
  bad_certificate = env_get("SSLIO_BAD_CERTIFICATE");
  if ((s =env_get("SSLIO_BUFIN"))) scan_ulong(s, &bufsizein);
  if ((s =env_get("SSLIO_BUFOU"))) scan_ulong(s, &bufsizeou);
  if (bufsizein < 64) bufsizein =64;
  if (bufsizeou < 64) bufsizeou =64;
  if ((s =env_get("SSLIO_HANDSHAKE_TIMEOUT")))
    scan_ulong(s, &handshake_timeout);
  if (handshake_timeout < 1) handshake_timeout =1;

  if (pipe(encpipe) == -1) fatalm("unable to create pipe for encoding");
  if (pipe(decpipe) == -1) fatalm("unable to create pipe for decoding");
  if ((pid =fork()) == -1) fatalm("unable to fork");
  if (pid == 0) {
    if (close(encpipe[1]) == -1)
      fatalm("unable to close encoding pipe output");
    if (close(decpipe[0]) == -1)
      fatalm("unable to close decoding pipe input");
    if (newsession) if (matrixSslOpen() < 0) fatalm("unable to initialize ssl");
    if (root) {
      if (chdir(root) == -1) fatalm("unable to change to new root directory");
      if (chroot(".") == -1) fatalm("unable to chroot");
    }
    if (ssluser) {
      /* drop permissions */
      if (setgroups(sslugid.gids, sslugid.gid) == -1)
        fatal("unable to set groups");
      if (setgid(*sslugid.gid) == -1) fatal("unable to set gid");
      if (prot_uid(sslugid.uid) == -1) fatalm("unable to set uid");
    }
    if (newsession) {
      if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
        if (client) fatalm("unable to read cert, key, or ca file");
        fatalm("unable to read cert or key file");
      }
      if (matrixSslNewSession(&ssl, keys, 0, client?0:SSL_FLAGS_SERVER) < 0)
        fatalmx("unable to create ssl session");
    }
    if (client)
      if (ca || bad_certificate) matrixSslSetCertValidator(ssl, &validate, 0);

    sig_catch(sig_term, sig_term_handler);
    sig_ignore(sig_pipe);
    doio();
    finish();
    _exit(0);
  }
  if (close(encpipe[0]) == -1) fatalm("unable to close encoding pipe input");
  if (close(decpipe[1]) == -1) fatalm("unable to close decoding pipe output");
  if (fd_move(fdstdin, decpipe[0]) == -1)
    fatalm("unable to setup filedescriptor for decoding");
  if (fd_move(fdstdou, encpipe[1]) == -1)
    fatalm("unable to setup filedescriptor for encoding");
  sslCloseOsdep();
  if (svuser) {
    if (setgroups(ugid.gids, ugid.gid) == -1)
      fatal("unable to set groups for prog");
    if (setgid(*ugid.gid) == -1) fatal("unable to set gid for prog");
    if (prot_uid(ugid.uid) == -1) fatalm("unable to set uid for prog");
  }
  pathexec(prog);
  fatalm("unable to run prog");
  return(111);
}
Esempio n. 8
0
int main(int argc, char **argv)
#endif
{
	sslSessionId_t		*sessionId;
	sslConn_t			*conn;
	sslKeys_t			*keys;
	WSADATA				wsaData;
	SOCKET				fd;
	short				cipherSuite;
	unsigned char		*ip, *c, *requestBuf;
	unsigned char		buf[1024];
	int					iterations, requests, connectAgain, status;
	int					quit, rc, bytes, i, j, err;
	time_t				t0, t1;
#if REUSE
	int					anonStatus;
#endif
#if VXWORKS
	int					argc;
	char				**argv;
	parseCmdLineArgs(arg1, &argc, &argv);
#endif /* VXWORKS */

#if WINCE
	int					argc;
	char				**argv;
	char				args[256];

/*
 *	parseCmdLineArgs expects an ASCII string and CE is unicoded, so convert
 *	the command line.  args will get hacked up, so you can't pass in a
 *	static string.
 */
	WideCharToMultiByte(CP_ACP, 0, lpCmdLine, -1, args, 256, NULL, NULL);

/*
 *	Parse the command line into an argv array.  This allocs memory, so
 *	we have to free argv when we're done.
 */
	parseCmdLineArgs(args, &argc, &argv);
#endif /* WINCE */

	conn = NULL;
/*
	First (optional) argument is ip address to connect to (port is hardcoded)
	Second (optional) argument is number of iterations to perform
	Third (optional) argument is number of keepalive HTTP requests
	Fourth (optional) argument is cipher suite number to use (0 for any)
*/
	ip = HTTPS_IP;
	iterations = ITERATIONS;
	requests = REQUESTS;
	cipherSuite = 0x0000;
	if (argc > 1) {
		ip = argv[1];
		if (argc > 2) {
			iterations = atoi(argv[2]);
			socketAssert(iterations > 0);
			if (argc > 3) {
				requests = atoi(argv[3]);
				socketAssert(requests > 0);
				if (argc > 4) {
					cipherSuite = (short)atoi(argv[4]);
				}
			}
		}
	}
/*
	Initialize Windows sockets (no-op on other platforms)
*/
	WSAStartup(MAKEWORD(1,1), &wsaData);
/*
	Initialize the MatrixSSL Library, and read in the certificate file
	used to validate the server.
*/
	if (matrixSslOpen() < 0) {
		fprintf(stderr, "matrixSslOpen failed, exiting...");
	}
	sessionId = NULL;
	if (matrixSslReadKeys(&keys, NULL, NULL, NULL, CAfile) < 0) {
		goto promptAndExit;
	}
/*
	Intialize loop control variables
*/
	quit = 0;
	connectAgain = 1;
	i = 1;
/*
	Just reuse the requestBuf and malloc to largest possible message size
*/
	requestBuf = malloc(sizeof(requestAgain));
	t0 = time(0);
/*
	Main ITERATIONS loop
*/
	while (!quit && (i < iterations)) {
/*
		sslConnect uses port and ip address to connect to SSL server.
		Generates a new session
*/
		if (connectAgain) {
			if ((fd = socketConnect(ip, HTTPS_PORT, &err)) == INVALID_SOCKET) {
				fprintf(stdout, "Error connecting to server %s:%d\n", ip, HTTPS_PORT);
				matrixSslFreeKeys(keys);
				goto promptAndExit;
			}
			if (sslConnect(&conn, fd, keys, sessionId, cipherSuite, certChecker) < 0) {
				quit = 1;
				socketShutdown(fd);
				fprintf(stderr, "Error connecting to %s:%d\n", ip, HTTPS_PORT);
				continue;
			}
			i++;
			connectAgain = 0;
			j = 1;
		}
		if (conn == NULL) {
			quit++;
			continue;
		}
/*
		Copy the HTTP request header into the buffer, based of whether or
		not we want httpReflector to keep the socket open or not
*/
		if (j == requests) {
			bytes = (int)strlen(request);
			memcpy(requestBuf, request, bytes);
		} else {
			bytes = (int)strlen(requestAgain);
			memcpy(requestBuf, requestAgain, bytes);
		}
/*
		Send request.  
		< 0 return indicates an error.
		0 return indicates not all data was sent and we must retry
		> 0 indicates that all requested bytes were sent
*/
writeMore:
		rc = sslWrite(conn, requestBuf, bytes, &status);
		if (rc < 0) {
			fprintf(stdout, "Internal sslWrite error\n");
			socketShutdown(conn->fd);
			sslFreeConnection(&conn);
			continue;
		} else if (rc == 0) {
			goto writeMore;
		}
/*
		Read response
		< 0 return indicates an error.
		0 return indicates an EOF or CLOSE_NOTIFY in this situation
		> 0 indicates that some bytes were read.  Keep reading until we see
		the /r/n/r/n from the response header.  There may be data following
		this header, but we don't try too hard to read it for this example.
*/
		c = buf;
readMore:
		if ((rc = sslRead(conn, c, sizeof(buf) - (int)(c - buf), &status)) > 0) {
			c += rc;
			if (c - buf < 4 || memcmp(c - 4, "\r\n\r\n", 4) != 0) {
				goto readMore;
			}
		} else {
			if (rc < 0) {
				fprintf(stdout, "sslRead error.  dropping connection.\n");
			}
			if (rc < 0 || status == SSLSOCKET_EOF ||
					status == SSLSOCKET_CLOSE_NOTIFY) {
				socketShutdown(conn->fd);
				sslFreeConnection(&conn);
				continue;
			}
			goto readMore;
		}
/*
		Determine if we want to do a pipelined HTTP request/response
*/
		if (j++ < requests) {
			fprintf(stdout, "R");
			continue;
		} else {
			fprintf(stdout, "C");
		}
/*
		Reuse the session.  Comment out these two lines to test the entire
		public key renegotiation each iteration
*/
#if REUSE
		matrixSslFreeSessionId(sessionId);
		matrixSslGetSessionId(conn->ssl, &sessionId);
/*
		This example shows how a user might want to limit a client to
		resuming handshakes only with authenticated servers.  In this
		example, the client will force any non-authenticated (anonymous)
		server to go through a complete handshake each time.  This is
		strictly an example of one policy decision an implementation 
		might wish to make.
*/
		matrixSslGetAnonStatus(conn->ssl, &anonStatus);
		if (anonStatus) {
			matrixSslFreeSessionId(sessionId);
			sessionId = NULL;
		}
#endif
/*
		Send a closure alert for clean shutdown of remote SSL connection
		This is for good form, some implementations just close the socket
*/
		sslWriteClosureAlert(conn);
/*
		Session done.  Connect again if more iterations remaining
*/
		socketShutdown(conn->fd);
		sslFreeConnection(&conn);
		connectAgain = 1;
	}

	t1 = time(0);
	free(requestBuf);
	matrixSslFreeSessionId(sessionId);
	if (conn && conn->ssl) {
		socketShutdown(conn->fd);
		sslFreeConnection(&conn);
	}
	fprintf(stdout, "\n%d connections in %d seconds (%f c/s)\n", 
		i, (int)(t1 - t0), (double)i / (t1 - t0));
	fprintf(stdout, "\n%d requests in %d seconds (%f r/s)\n", 
		i * requests, (int)(t1 - t0), 
		(double)(i * requests) / (t1 - t0));
/*
	Close listening socket, free remaining items
*/
	matrixSslFreeKeys(keys);
	matrixSslClose();
	WSACleanup();
promptAndExit:
	fprintf(stdout, "Press return to exit...\n");
	getchar();

#if WINCE || VXWORKS
	if (argv) {
		free((void*) argv);
	}
#endif /* WINCE */
	return 0;
}