aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--options.c84
-rw-r--r--options.h15
-rw-r--r--ptunnel.c31
3 files changed, 78 insertions, 52 deletions
diff --git a/options.c b/options.c
index bd13edb..6a47098 100644
--- a/options.c
+++ b/options.c
@@ -73,20 +73,20 @@ static const struct option_usage usage[] = {
"Set password (must be same on client and proxy)\n"
"If no password is set, you will be asked during runtime.\n"
},
- {NULL, 0, OPT_BOOL, {.unum = 0},
+ {NULL, 0, OPT_BOOL, {.num = 0},
"Toggle use of UDP instead of ICMP. Proxy will listen on port 53 (must be root).\n"
},
- {NULL, 0, OPT_BOOL, {.unum = 0},
+ {NULL, 0, OPT_BOOL, {.num = 0},
"Run proxy in unprivileged mode. This causes the proxy to forward\n"
"packets using standard echo requests, instead of crafting custom echo replies.\n"
"Unprivileged mode will only work on some systems, and is in general less reliable\n"
"than running in privileged mode.\n"
},
#ifndef WIN32
- {NULL, 0, OPT_BOOL, {.unum = 0},
+ {NULL, 0, OPT_BOOL, {.num = 0},
"Run in background, the PID will be written in the file supplied as argument\n"
},
- {NULL, 0, OPT_BOOL, {.unum = 0},
+ {NULL, 0, OPT_BOOL, {.num = 0},
"Output debug to syslog instead of standard out.\n"
},
{"user", 0, OPT_STR, {.str = "nobody"},
@@ -100,7 +100,7 @@ static const struct option_usage usage[] = {
},
#endif
#ifdef HAVE_SELINUX
- {NULL, 0, OPT_BOOL, {.unum = 0},
+ {NULL, 0, OPT_BOOL, {.num = 0},
"Set SELinux context when all there is left to do are network I/O operations\n"
"To combine with -chroot you will have to `mount --bind /proc /chrootdir/proc`\n"
},
@@ -126,8 +126,6 @@ static struct option long_options[] = {
#ifndef WIN32
{"daemon", no_argument, 0, 'd'},
{"syslog", no_argument, 0, 'S'},
-#endif
-#ifndef WIN32
{"user", required_argument, 0, 'u'},
{"group", required_argument, 0, 'g'},
{"chroot", required_argument, 0, 't'},
@@ -152,6 +150,12 @@ static const void *get_default_optval(enum option_type opttype, const char *optn
}
static void set_options_defaults(void) {
+#ifndef WIN32
+ char *tmp;
+ struct passwd *pwnam;
+ struct group *grnam;
+#endif
+
memset(&opts, 0, sizeof(opts));
opts.magic = *(uint32_t *) get_default_optval(OPT_HEX32, "magic");
opts.mode = kMode_proxy;
@@ -161,10 +165,29 @@ static void set_options_defaults(void) {
opts.given_dst_port = *(uint32_t *) get_default_optval(OPT_DEC32, "remote-port");
opts.max_tunnels = *(uint32_t *) get_default_optval(OPT_DEC32, "connections");
opts.log_level = *(int *) get_default_optval(OPT_DEC32, "verbosity");
- opts.pcap_device = strdup((char *)get_default_optval(OPT_STR, "libpcap"));
- opts.log_file = fopen(*(char **) get_default_optval(OPT_STR, "logfile"), "a");
+ opts.pcap_device = strdup(*(char **)get_default_optval(OPT_STR, "libpcap"));
+ opts.log_path = strdup(*(char **)get_default_optval(OPT_STR, "logfile"));
+ opts.log_file = stdout;
opts.print_stats = *(int *) get_default_optval(OPT_BOOL, "statistics");
+ opts.udp = *(int *) get_default_optval(OPT_BOOL, "udp");
+ opts.unprivileged = *(int *) get_default_optval(OPT_BOOL, "unprivileged");
#ifndef WIN32
+ errno = 0;
+ tmp = *(char **) get_default_optval(OPT_STR, "user");
+ if (NULL == (pwnam = getpwnam(tmp)))
+ pt_log(kLog_error, "%s: %s\n", tmp, errno ? strerror(errno) : "unknown user");
+ else {
+ opts.uid = pwnam->pw_uid;
+ if (!opts.gid)
+ opts.gid = pwnam->pw_gid;
+ }
+
+ errno = 0;
+ tmp = *(char **) get_default_optval(OPT_STR, "group");
+ if (NULL == (grnam = getgrnam(tmp)))
+ pt_log(kLog_error, "%s: %s\n", tmp, errno ? strerror(errno) : "unknown group");
+ else
+ opts.gid = grnam->gr_gid;
#endif
}
@@ -271,6 +294,7 @@ int parse_options(int argc, char **argv) {
struct passwd *pwnam;
struct group *grnam;
#endif
+ FILE *tmp_log;
assert( ARRAY_SIZE(long_options) == ARRAY_SIZE(usage) );
@@ -279,7 +303,7 @@ int parse_options(int argc, char **argv) {
/* parse command line arguments */
while (1) {
- c = getopt_long(argc, argv, "m:p:l::r::R::c:v:a:o::sdSx:u:g:t:eh", &long_options[0], &optind);
+ c = getopt_long(argc, argv, "m:p:l::r::R::c:v:a:o::sdSx:u::g::t:eh", &long_options[0], &optind);
if (c == -1) break;
switch (c) {
@@ -321,27 +345,22 @@ int parse_options(int argc, char **argv) {
break;
case 'o':
if (optarg) {
- if (opts.log_file)
- fclose(opts.log_file);
- opts.log_file = fopen(optarg, "a");
- }
- if (!opts.log_file) {
- pt_log(kLog_error, "Failed to open log file: \"%s\", Cause: %s\n", (optarg ? optarg : "default"), strerror(errno));
- pt_log(kLog_error, "Reverting log to standard out.\n");
- } else {
- has_logfile = 1;
+ if (opts.log_path)
+ free(opts.log_path);
+ opts.log_path = strdup(optarg);
}
+ has_logfile = 1;
break;
case 's':
opts.print_stats = !opts.print_stats;
break;
case 'x':
- opts.password_digest = (unsigned char *)calloc(MD5_LEN, sizeof(unsigned char));
+ opts.password = strdup(optarg);
pt_log(kLog_debug, "Password set - unauthenicated connections will be refused.\n");
// Compute the password digest
md5_init(&state);
- md5_append(&state, (md5_byte_t*)optarg, strlen(optarg));
- md5_finish(&state, opts.password_digest);
+ md5_append(&state, (md5_byte_t*)optarg, strlen(opts.password));
+ md5_finish(&state, &opts.password_digest[0]);
// Hide the password in process listing
memset(optarg, '*', strlen(optarg));
break;
@@ -355,6 +374,8 @@ int parse_options(int argc, char **argv) {
opts.use_syslog = 1;
break;
case 'u':
+ if (!optarg)
+ break;
errno = 0;
if (NULL == (pwnam = getpwnam(optarg))) {
pt_log(kLog_error, "%s: %s\n", optarg, errno ? strerror(errno) : "unknown user");
@@ -365,6 +386,8 @@ int parse_options(int argc, char **argv) {
opts.gid = pwnam->pw_gid;
break;
case 'g':
+ if (!optarg)
+ break;
errno = 0;
if (NULL == (grnam = getgrnam(optarg))) {
pt_log(kLog_error, "%s: %s\n", optarg, errno ? strerror(errno) : "unknown group");
@@ -381,7 +404,7 @@ int parse_options(int argc, char **argv) {
case 'u':
case 'g':
case 't':
- pt_log(kLog_error, "%s: feature not supported", optarg);
+ pt_log(kLog_error, "%s: feature not supported\n", optarg);
exit(1);
#endif
case 'e':
@@ -389,7 +412,7 @@ int parse_options(int argc, char **argv) {
opts.selinux_context = strdup(optarg);
break;
#else
- pt_log(kLog_error, "%s: feature not supported", optarg);
+ pt_log(kLog_error, "%s: feature not supported\n", optarg);
exit(1);
#endif
case 'h':
@@ -398,7 +421,7 @@ int parse_options(int argc, char **argv) {
case 0: /* long opt only */
break;
default:
- pt_log(kLog_error, "%s: option unknown", optarg);
+ pt_log(kLog_error, "\"%s\": option unknown\n", argv[optind - 1]);
break;
}
}
@@ -409,10 +432,13 @@ int parse_options(int argc, char **argv) {
}
opts.given_dst_ip = *(uint32_t*)host_ent->h_addr_list[0];
- if (!has_logfile) {
- if (opts.log_file)
- fclose(opts.log_file);
- opts.log_file = stdout;
+ if (has_logfile && opts.log_path) {
+ pt_log(kLog_info, "Open Logfile: \"%s\"\n", opts.log_path);
+ tmp_log = fopen(opts.log_path, "a");
+ if (!tmp_log) {
+ pt_log(kLog_error, "Failed to open log file: \"%s\", Cause: %s\n", opts.log_path, strerror(errno));
+ pt_log(kLog_error, "Reverting log to standard out.\n");
+ } else opts.log_file = tmp_log;
}
return 0;
diff --git a/options.h b/options.h
index b2f17aa..564f1a9 100644
--- a/options.h
+++ b/options.h
@@ -11,6 +11,7 @@
#endif
#include "ptunnel.h"
+#include "md5.h"
struct options {
@@ -34,19 +35,19 @@ struct options {
/** Device to capture packets from */
char *pcap_device;
/** Usually stdout, but can be altered by the user */
+ char *log_path;
FILE *log_file;
/** Print more detailed traffic statistics if non zero value */
int print_stats;
- /** Password-Digest (must be the same on proxy and client for authentication to succeed) */
- unsigned char *password_digest;
+ /** Password (must be the same on proxy and client for authentica tion to succeed) */
+ char *password;
+ /** MD5 digest of challenge+password */
+ md5_byte_t password_digest[kMD5_digest_size];
/** use UDP instead of ICMP */
int udp;
/** unpriviledged mode */
int unprivileged;
-#ifdef HAVE_SELINUX
- char *selinux_context;
-#endif
#ifndef WIN32
/** run as daemon if non zero value */
int daemonize;
@@ -61,6 +62,10 @@ struct options {
/** PIDFILE */
FILE *pid_file;
#endif
+
+#ifdef HAVE_SELINUX
+ char *selinux_context;
+#endif
};
extern struct options opts;
diff --git a/ptunnel.c b/ptunnel.c
index 3f9028d..f377306 100644
--- a/ptunnel.c
+++ b/ptunnel.c
@@ -73,8 +73,6 @@
#include <selinux/selinux.h>
static char *selinux_context = NULL;
#endif
- static uid_t uid = 0;
- static gid_t gid = 0;
static char *root_dir = NULL;
static bool daemonize = false;
static FILE *pid_file = NULL;
@@ -93,8 +91,6 @@ int
uint32_t
*seq_expiry_tbl = 0; // Table indicating when a connection ID is allowable (used by proxy)
char
- *password = 0, // Password (must be the same on proxy and client for authentication to succeed)
- password_digest[kMD5_digest_size], // MD5 digest of password
*pcap_device = 0; // Device to capture packets from
// Some buffer constants
@@ -135,7 +131,7 @@ int main(int argc, char *argv[]) {
// Seed random generator; it'll be used in combination with a timestamp
// when generating authentication challenges.
srand(time(0));
- memset(password_digest, 0, kMD5_digest_size);
+ memset(opts.password_digest, 0, kMD5_digest_size);
/* The seq_expiry_tbl is used to prevent the remote ends from prematurely
re-using a sequence number.
@@ -491,15 +487,15 @@ void* pt_proxy(void *args) {
#ifndef WIN32
#ifdef HAVE_SELINUX
- if (uid || gid || selinux_context)
+ if (opts.uid || opts.gid || selinux_context)
#else
- if (uid || gid)
+ if (opts.uid || opts.gid)
#endif
pt_log(kLog_info, "Dropping privileges now.\n");
- if (gid && -1 == setgid(gid))
- pt_log(kLog_error, "setgid(%d): %s\n", gid, strerror(errno));
- if (uid && -1 == setuid(uid))
- pt_log(kLog_error, "setuid(%d): %s\n", uid, strerror(errno));
+ if (opts.gid && -1 == setgid(opts.gid))
+ pt_log(kLog_error, "setgid(%d): %s\n", opts.gid, strerror(errno));
+ if (opts.uid && -1 == setuid(opts.uid))
+ pt_log(kLog_error, "setuid(%d): %s\n", opts.uid, strerror(errno));
#ifdef HAVE_SELINUX
if (NULL != selinux_context && -1 == setcon(selinux_context))
pt_log(kLog_error, "setcon(%s) failed: %s\n", selinux_context, strerror(errno));
@@ -545,7 +541,7 @@ void* pt_proxy(void *args) {
// Only handle traffic if there is traffic on the socket, we have
// room in our send window AND we either don't use a password, or
// have been authenticated.
- if (FD_ISSET(cur->sock, &set) && cur->send_wait_ack < kPing_window_size && (!password || cur->authenticated)) {
+ if (FD_ISSET(cur->sock, &set) && cur->send_wait_ack < kPing_window_size && (!opts.password || cur->authenticated)) {
bytes = recv(cur->sock, cur->buf, tcp_receive_buf_len, 0);
if (bytes <= 0) {
pt_log(kLog_info, "Connection closed or lost.\n");
@@ -809,7 +805,7 @@ void handle_packet(char *buf, int bytes, int is_pcap, struct sockaddr_in *addr,
pt_log(kLog_info, "Destination administratively prohibited!\n");
return;
}
- if (password)
+ if (opts.password)
init_state = kProto_authenticate;
else
init_state = kProto_data;
@@ -842,7 +838,7 @@ void handle_packet(char *buf, int bytes, int is_pcap, struct sockaddr_in *addr,
challenge = (challenge_t*)pt_pkt->data;
// If client: Compute response to challenge
if (type_flag == kUser_flag) {
- if (!password) {
+ if (!opts.password) {
pt_log(kLog_error, "This proxy requires a password! Please supply one using the -x switch.\n");
send_termination_msg(cur, icmp_sock);
cur->should_remove = 1;
@@ -884,7 +880,7 @@ void handle_packet(char *buf, int bytes, int is_pcap, struct sockaddr_in *addr,
// The proxy will ignore any other packets from the client
// until it has been authenticated. The packet resend mechanism
// insures that this isn't problematic.
- if (type_flag == kProxy_flag && password && cur && !cur->authenticated) {
+ if (type_flag == kProxy_flag && opts.password && cur && !cur->authenticated) {
pt_log(kLog_debug, "Ignoring packet with seq-no %d - not authenticated yet.\n", pt_pkt->seq_no);
return;
}
@@ -1344,12 +1340,11 @@ challenge_t* generate_challenge(void) {
the challenge data.
*/
void generate_response(challenge_t *challenge) {
- md5_byte_t *buf;
+ md5_byte_t buf[sizeof(challenge_t)+kMD5_digest_size];
md5_state_t state;
- buf = malloc(sizeof(challenge_t)+kMD5_digest_size);
memcpy(buf, challenge, sizeof(challenge_t));
- memcpy(&buf[sizeof(challenge_t)], password_digest, kMD5_digest_size);
+ memcpy(&buf[sizeof(challenge_t)], opts.password_digest, kMD5_digest_size);
memset(challenge, 0, sizeof(challenge_t));
md5_init(&state);
md5_append(&state, buf, sizeof(challenge_t)+kMD5_digest_size);