From 2a3d17ed182608cf60d731a237f9f926c28db522 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 9 Dec 2010 11:21:04 +0000 Subject: Added "management-external-key" option. This option can be used instead of "key" in client mode, and allows the client to run without the need to load the actual private key. When the SSL protocol needs to perform an RSA sign operation, the data to be signed will be sent to the management interface via a notification as follows: >RSA_SIGN:[BASE64_DATA] The management interface client should then sign BASE64_DATA using the private key and return the signature as follows: rsa-sig [BASE64_SIG_LINE] . . . END This capability is intended to allow the use of arbitrary cryptographic service providers with OpenVPN via the management interface. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6708 e7ae566f-a301-0410-adde-c780ea21d3b5 --- base64.c | 17 ++++- base64.h | 4 +- buffer.c | 2 +- manage.c | 204 +++++++++++++++++++++++++++++++++++++++++++++-------------- manage.h | 24 ++++++- misc.c | 2 +- ntlm.c | 2 +- options.c | 8 +++ ssl.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- syshead.h | 15 +++++ 10 files changed, 433 insertions(+), 59 deletions(-) diff --git a/base64.c b/base64.c index 3449ae5..8f0fb6c 100644 --- a/base64.c +++ b/base64.c @@ -33,7 +33,7 @@ #include "syshead.h" -#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) +#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY) #include "base64.h" @@ -115,22 +115,35 @@ token_decode(const char *token) } int -base64_decode(const char *str, void *data) +base64_decode(const char *str, void *data, int size) { const char *p; unsigned char *q; + unsigned char *e = NULL; q = data; + if (size >= 0) + e = q + size; for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) { unsigned int val = token_decode(p); unsigned int marker = (val >> 24) & 0xff; if (val == DECODE_ERROR) return -1; + if (e && q >= e) + return -1; *q++ = (val >> 16) & 0xff; if (marker < 2) + { + if (e && q >= e) + return -1; *q++ = (val >> 8) & 0xff; + } if (marker < 1) + { + if (e && q >= e) + return -1; *q++ = val & 0xff; + } } return q - (unsigned char *) data; } diff --git a/base64.h b/base64.h index 968d18d..64439a0 100644 --- a/base64.h +++ b/base64.h @@ -34,10 +34,10 @@ #ifndef _BASE64_H_ #define _BASE64_H_ -#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) +#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY) int base64_encode(const void *data, int size, char **str); -int base64_decode(const char *str, void *data); +int base64_decode(const char *str, void *data, int size); #endif diff --git a/buffer.c b/buffer.c index 5108429..2952767 100644 --- a/buffer.c +++ b/buffer.c @@ -906,7 +906,7 @@ buffer_list_free (struct buffer_list *ol) bool buffer_list_defined (const struct buffer_list *ol) { - return ol->head != NULL; + return ol && ol->head != NULL; } void diff --git a/manage.c b/manage.c index 820621e..0c99d0f 100644 --- a/manage.c +++ b/manage.c @@ -101,6 +101,10 @@ man_help () #ifdef MANAGEMENT_PF msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)"); #endif +#endif +#ifdef MANAGMENT_EXTERNAL_KEY + msg (M_CLIENT, "rsa-sig : Enter an RSA signature in response to >RSA_SIGN challenge"); + msg (M_CLIENT, " Enter signature base64 on subsequent lines followed by END"); #endif msg (M_CLIENT, "signal s : Send signal s to daemon,"); msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2."); @@ -768,49 +772,31 @@ man_hold (struct management *man, const char *cmd) msg (M_CLIENT, "SUCCESS: hold=%d", BOOL_CAST(man->settings.flags & MF_HOLD)); } -#ifdef MANAGEMENT_DEF_AUTH - -static bool -parse_cid (const char *str, unsigned long *cid) -{ - if (sscanf (str, "%lu", cid) == 1) - return true; - else - { - msg (M_CLIENT, "ERROR: cannot parse CID"); - return false; - } -} +#ifdef MANAGEMENT_IN_EXTRA -static bool -parse_kid (const char *str, unsigned int *kid) -{ - if (sscanf (str, "%u", kid) == 1) - return true; - else - { - msg (M_CLIENT, "ERROR: cannot parse KID"); - return false; - } -} +#define IER_RESET 0 +#define IER_NEW 1 +#define IER_CONDRESET 2 static void -in_extra_reset (struct man_connection *mc, const bool new) +in_extra_reset (struct man_connection *mc, const int mode) { - if (mc) + if (mc && (mc->in_extra_cmd < IEC_STATEFUL_BASE || mode != IER_CONDRESET)) { - if (!new) + if (mode != IER_NEW) { mc->in_extra_cmd = IEC_UNDEF; +#ifdef MANAGEMENT_DEF_AUTH mc->in_extra_cid = 0; mc->in_extra_kid = 0; +#endif } if (mc->in_extra) { buffer_list_free (mc->in_extra); mc->in_extra = NULL; } - if (new) + if (mode == IER_NEW) mc->in_extra = buffer_list_new (0); } } @@ -820,6 +806,7 @@ in_extra_dispatch (struct management *man) { switch (man->connection.in_extra_cmd) { +#ifdef MANAGEMENT_DEF_AUTH case IEC_CLIENT_AUTH: if (man->persist.callback.client_auth) { @@ -846,6 +833,7 @@ in_extra_dispatch (struct management *man) msg (M_CLIENT, "ERROR: The client-auth command is not supported by the current daemon mode"); } break; +#endif #ifdef MANAGEMENT_PF case IEC_CLIENT_PF: if (man->persist.callback.client_pf) @@ -870,8 +858,41 @@ in_extra_dispatch (struct management *man) } break; #endif +#ifdef MANAGMENT_EXTERNAL_KEY + case IEC_RSA_SIGN: + man->connection.in_extra_cmd = IEC_RSA_SIGN_FINAL; + return; +#endif + } + in_extra_reset (&man->connection, IER_RESET); +} + +#endif /* MANAGEMENT_IN_EXTRA */ + +#ifdef MANAGEMENT_DEF_AUTH + +static bool +parse_cid (const char *str, unsigned long *cid) +{ + if (sscanf (str, "%lu", cid) == 1) + return true; + else + { + msg (M_CLIENT, "ERROR: cannot parse CID"); + return false; + } +} + +static bool +parse_kid (const char *str, unsigned int *kid) +{ + if (sscanf (str, "%u", kid) == 1) + return true; + else + { + msg (M_CLIENT, "ERROR: cannot parse KID"); + return false; } - in_extra_reset (&man->connection, false); } static void @@ -884,7 +905,7 @@ man_client_auth (struct management *man, const char *cid_str, const char *kid_st && parse_kid (kid_str, &mc->in_extra_kid)) { mc->in_extra_cmd = IEC_CLIENT_AUTH; - in_extra_reset (mc, true); + in_extra_reset (mc, IER_NEW); if (!extra) in_extra_dispatch (man); } @@ -980,11 +1001,28 @@ man_client_pf (struct management *man, const char *cid_str) if (parse_cid (cid_str, &mc->in_extra_cid)) { mc->in_extra_cmd = IEC_CLIENT_PF; - in_extra_reset (mc, true); + in_extra_reset (mc, IER_NEW); } } -#endif +#endif /* MANAGEMENT_PF */ +#endif /* MANAGEMENT_DEF_AUTH */ + +#ifdef MANAGMENT_EXTERNAL_KEY + +static void +man_rsa_sig (struct management *man) +{ + struct man_connection *mc = &man->connection; + if (mc->in_extra_cmd == IEC_RSA_SIGN_PRE) + { + in_extra_reset (&man->connection, IER_NEW); + mc->in_extra_cmd = IEC_RSA_SIGN; + } + else + msg (M_CLIENT, "ERROR: The rsa-sig command is not currently available"); +} + #endif static void @@ -1250,6 +1288,12 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch } #endif #endif +#ifdef MANAGMENT_EXTERNAL_KEY + else if (streq (p[0], "rsa-sig")) + { + man_rsa_sig (man); + } +#endif #ifdef ENABLE_PKCS11 else if (streq (p[0], "pkcs11-id-count")) { @@ -1626,8 +1670,8 @@ man_reset_client_socket (struct management *man, const bool exiting) man->connection.state = MS_INITIAL; command_line_reset (man->connection.in); buffer_list_reset (man->connection.out); -#ifdef MANAGEMENT_DEF_AUTH - in_extra_reset (&man->connection, false); +#ifdef MANAGEMENT_IN_EXTRA + in_extra_reset (&man->connection, IER_RESET); #endif msg (D_MANAGEMENT, "MANAGEMENT: Client disconnected"); } @@ -1666,8 +1710,8 @@ man_process_command (struct management *man, const char *line) CLEAR (parms); so = status_open (NULL, 0, -1, &man->persist.vout, 0); -#ifdef MANAGEMENT_DEF_AUTH - in_extra_reset (&man->connection, false); +#ifdef MANAGEMENT_IN_EXTRA + in_extra_reset (&man->connection, IER_CONDRESET); #endif if (man_password_needed (man)) @@ -1751,18 +1795,13 @@ man_read (struct management *man) const unsigned char *line; while ((line = command_line_get (man->connection.in))) { -#ifdef MANAGEMENT_DEF_AUTH +#ifdef MANAGEMENT_IN_EXTRA if (man->connection.in_extra) { if (!strcmp ((char *)line, "END")) - { - in_extra_dispatch (man); - in_extra_reset (&man->connection, false); - } + in_extra_dispatch (man); else - { - buffer_list_push (man->connection.in_extra, line); - } + buffer_list_push (man->connection.in_extra, line); } else #endif @@ -2063,8 +2102,8 @@ man_connection_close (struct management *man) command_line_free (mc->in); if (mc->out) buffer_list_free (mc->out); -#ifdef MANAGEMENT_DEF_AUTH - in_extra_reset (&man->connection, false); +#ifdef MANAGEMENT_IN_EXTRA + in_extra_reset (&man->connection, IER_RESET); #endif man_connection_clear (mc); } @@ -2387,7 +2426,7 @@ management_learn_addr (struct management *management, gc_free (&gc); } -#endif +#endif /* MANAGEMENT_DEF_AUTH */ void management_echo (struct management *man, const char *string, const bool pull) @@ -2693,6 +2732,7 @@ man_standalone_event_loop (struct management *man, volatile int *signal_received #define MWCC_PASSWORD_WAIT (1<<0) #define MWCC_HOLD_WAIT (1<<1) +#define MWCC_OTHER_WAIT (1<<2) /* * Block until client connects @@ -2710,6 +2750,8 @@ man_wait_for_client_connection (struct management *man, msg (D_MANAGEMENT, "Need password(s) from management interface, waiting..."); if (flags & MWCC_HOLD_WAIT) msg (D_MANAGEMENT, "Need hold release from management interface, waiting..."); + if (flags & MWCC_OTHER_WAIT) + msg (D_MANAGEMENT, "Need information from management interface, waiting..."); do { man_standalone_event_loop (man, signal_received, expire); if (signal_received && *signal_received) @@ -2873,6 +2915,74 @@ management_query_user_pass (struct management *man, return ret; } +#ifdef MANAGMENT_EXTERNAL_KEY + +char * /* returns allocated base64 signature */ +management_query_rsa_sig (struct management *man, + const char *b64_data) +{ + struct gc_arena gc = gc_new (); + char *ret = NULL; + volatile int signal_received = 0; + struct buffer alert_msg = clear_buf(); + struct buffer *buf; + const bool standalone_disabled_save = man->persist.standalone_disabled; + + if (man_standalone_ok (man)) + { + man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ + man->persist.special_state_msg = NULL; + + in_extra_reset (&man->connection, IER_RESET); + man->connection.in_extra_cmd = IEC_RSA_SIGN_PRE; + + alert_msg = alloc_buf_gc (strlen(b64_data)+64, &gc); + buf_printf (&alert_msg, ">RSA_SIGN:%s", b64_data); + + man_wait_for_client_connection (man, &signal_received, 0, MWCC_OTHER_WAIT); + + if (signal_received) + goto done; + + man->persist.special_state_msg = BSTR (&alert_msg); + msg (M_CLIENT, "%s", man->persist.special_state_msg); + + /* run command processing event loop until we get our signature */ + do + { + man_standalone_event_loop (man, &signal_received, 0); + if (!signal_received) + man_check_for_signals (&signal_received); + if (signal_received) + goto done; + } while (man->connection.in_extra_cmd != IEC_RSA_SIGN_FINAL); + + if (buffer_list_defined(man->connection.in_extra)) + { + buffer_list_aggregate (man->connection.in_extra, 2000); + buf = buffer_list_peek (man->connection.in_extra); + if (buf && BLEN(buf) > 0) + { + ret = (char *) malloc(BLEN(buf)+1); + check_malloc_return(ret); + memcpy(ret, buf->data, BLEN(buf)); + ret[BLEN(buf)] = '\0'; + } + } + } + + done: + /* revert state */ + man->persist.standalone_disabled = standalone_disabled_save; + man->persist.special_state_msg = NULL; + in_extra_reset (&man->connection, IER_RESET); + + gc_free (&gc); + return ret; +} + +#endif + /* * Return true if management_hold() would block */ diff --git a/manage.h b/manage.h index 6a9ccd8..697ddf8 100644 --- a/manage.h +++ b/manage.h @@ -264,15 +264,22 @@ struct man_connection { struct command_line *in; struct buffer_list *out; -#ifdef MANAGEMENT_DEF_AUTH +#ifdef MANAGEMENT_IN_EXTRA # define IEC_UNDEF 0 # define IEC_CLIENT_AUTH 1 # define IEC_CLIENT_PF 2 + +# define IEC_STATEFUL_BASE 16 +# define IEC_RSA_SIGN_PRE 16 +# define IEC_RSA_SIGN 17 +# define IEC_RSA_SIGN_FINAL 18 int in_extra_cmd; + struct buffer_list *in_extra; +#ifdef MANAGEMENT_DEF_AUTH unsigned long in_extra_cid; unsigned int in_extra_kid; - struct buffer_list *in_extra; int env_filter_level; +#endif #endif struct event_set *es; @@ -285,6 +292,10 @@ struct man_connection { const char *up_query_type; int up_query_mode; struct user_pass up_query; + +#ifdef MANAGMENT_EXTERNAL_KEY + struct buffer_list *rsa_sig; +#endif }; struct management @@ -314,6 +325,9 @@ struct management *management_init (void); # define MF_CLIENT_PF (1<<7) #endif # define MF_UNIX_SOCK (1<<8) +#ifdef MANAGMENT_EXTERNAL_KEY +# define MF_EXTERNAL_KEY (1<<9) +#endif bool management_open (struct management *man, const char *addr, @@ -374,6 +388,12 @@ void management_learn_addr (struct management *management, const bool primary); #endif +#ifdef MANAGMENT_EXTERNAL_KEY + +char *management_query_rsa_sig (struct management *man, const char *b64_data); + +#endif + static inline bool management_connected (const struct management *man) { diff --git a/misc.c b/misc.c index f5a3b89..0f9dfcc 100644 --- a/misc.c +++ b/misc.c @@ -1607,7 +1607,7 @@ get_auth_challenge (const char *auth_challenge, struct gc_arena *gc) if (!buf_parse(&b, ':', work, len)) return NULL; ac->user = (char *) gc_malloc (strlen(work)+1, true, gc); - base64_decode(work, (void*)ac->user); + base64_decode(work, (void*)ac->user, -1); /* parse challenge text */ ac->challenge_text = string_alloc(BSTR(&b), gc); diff --git a/ntlm.c b/ntlm.c index 0453358..4dfeed3 100644 --- a/ntlm.c +++ b/ntlm.c @@ -242,7 +242,7 @@ ntlm_phase_3 (const struct http_proxy_info *p, const char *phase_2, struct gc_ar /* pad to 21 bytes */ memset (md4_hash + 16, 0, 5); - ret_val = base64_decode( phase_2, (void *)buf2); + ret_val = base64_decode( phase_2, (void *)buf2, -1); if (ret_val < 0) return NULL; diff --git a/options.c b/options.c index b95ceb5..95b6254 100644 --- a/options.c +++ b/options.c @@ -3636,6 +3636,14 @@ add_option (struct options *options, options->management_flags |= MF_CONNECT_AS_CLIENT; options->management_write_peer_info_file = p[1]; } +#ifdef MANAGMENT_EXTERNAL_KEY + else if (streq (p[0], "management-external-key")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->management_flags |= MF_EXTERNAL_KEY; + options->priv_key_file = "EXTERNAL_PRIVATE_KEY"; + } +#endif #ifdef MANAGEMENT_DEF_AUTH else if (streq (p[0], "management-client-auth")) { diff --git a/ssl.c b/ssl.c index 0f93cef..9ab907c 100644 --- a/ssl.c +++ b/ssl.c @@ -48,6 +48,7 @@ #include "gremlin.h" #include "pkcs11.h" #include "list.h" +#include "base64.h" #ifdef WIN32 #include "cryptoapi.h" @@ -1315,6 +1316,195 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret) } } +#ifdef MANAGMENT_EXTERNAL_KEY + +/* encrypt */ +static int +rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + ASSERT(0); + return -1; +} + +/* verify arbitrary data */ +static int +rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + ASSERT(0); + return -1; +} + +/* decrypt */ +static int +rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + ASSERT(0); + return -1; +} + +/* called at RSA_free */ +static int +rsa_finish(RSA *rsa) +{ + free ((void*)rsa->meth); + rsa->meth = NULL; + return 1; +} + +/* sign arbitrary data */ +static int +rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + /* optional app data in rsa->meth->app_data; */ + char *in_b64 = NULL; + char *out_b64 = NULL; + int ret = -1; + int len; + + if (padding != RSA_PKCS1_PADDING) + { + RSAerr (RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + goto done; + } + + /* convert 'from' to base64 */ + if (base64_encode (from, flen, &in_b64) <= 0) + goto done; + + /* call MI for signature */ + if (management) + out_b64 = management_query_rsa_sig (management, in_b64); + if (!out_b64) + goto done; + + /* decode base64 signature to binary */ + len = RSA_size(rsa); + ret = base64_decode (out_b64, to, len); + + /* verify length */ + if (ret != len) + ret = -1; + + done: + if (in_b64) + free (in_b64); + if (out_b64) + free (out_b64); + return ret; +} + +static int +use_external_private_key (SSL_CTX *ssl_ctx, X509 *cert) +{ + RSA *rsa = NULL; + RSA *pub_rsa; + RSA_METHOD *rsa_meth; + + /* allocate custom RSA method object */ + ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD); + rsa_meth->name = "OpenVPN external private key RSA Method"; + rsa_meth->rsa_pub_enc = rsa_pub_enc; + rsa_meth->rsa_pub_dec = rsa_pub_dec; + rsa_meth->rsa_priv_enc = rsa_priv_enc; + rsa_meth->rsa_priv_dec = rsa_priv_dec; + rsa_meth->init = NULL; + rsa_meth->finish = rsa_finish; + rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; + rsa_meth->app_data = NULL; + + /* allocate RSA object */ + rsa = RSA_new(); + if (rsa == NULL) + { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* get the public key */ + ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */ + pub_rsa = cert->cert_info->key->pkey->pkey.rsa; + + /* initialize RSA object */ + rsa->n = BN_dup(pub_rsa->n); + rsa->flags |= RSA_FLAG_EXT_PKEY; + if (!RSA_set_method(rsa, rsa_meth)) + goto err; + + /* bind our custom RSA object to ssl_ctx */ + if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa)) + goto err; + + RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ + return 1; + + err: + if (rsa) + RSA_free(rsa); + else + { + if (rsa_meth) + free(rsa_meth); + } + return 0; +} + +/* + * Basically a clone of SSL_CTX_use_certificate_file, but also return + * the x509 object. + */ +static int +use_certificate_file(SSL_CTX *ctx, const char *file, int type, X509 **x509) +{ + int j; + BIO *in; + int ret=0; + X509 *x=NULL; + + in=BIO_new(BIO_s_file_internal()); + if (in == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in,file) <= 0) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_ASN1) + { + j=ERR_R_ASN1_LIB; + x=d2i_X509_bio(in,NULL); + } + else if (type == SSL_FILETYPE_PEM) + { + j=ERR_R_PEM_LIB; + x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata); + } + else + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (x == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,j); + goto end; + } + + ret=SSL_CTX_use_certificate(ctx,x); + end: + if (in != NULL) + BIO_free(in); + if (x509) + *x509 = x; + return(ret); +} + +#endif + #if ENABLE_INLINE_FILES static int @@ -1422,7 +1612,7 @@ use_inline_load_client_CA_file (SSL_CTX *ctx, const char *ca_string) } static int -use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string) +use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string, X509 **x509) { BIO *in = NULL; X509 *x = NULL; @@ -1446,6 +1636,8 @@ use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string) X509_free (x); if (in) BIO_free (in); + if (x509) + *x509 = x; return ret; } @@ -1490,6 +1682,7 @@ init_ssl (const struct options *options) DH *dh; BIO *bio; bool using_cert_file = false; + X509 *my_cert = NULL; ERR_clear_error (); @@ -1589,7 +1782,6 @@ init_ssl (const struct options *options) management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); #endif PKCS12_free(p12); - msg (M_INFO, "OpenSSL ERROR code: %d", (ERR_GET_REASON (ERR_peek_error()))); // fixme goto err; } } @@ -1657,18 +1849,32 @@ init_ssl (const struct options *options) #if ENABLE_INLINE_FILES if (!strcmp (options->cert_file, INLINE_FILE_TAG) && options->cert_file_inline) { - if (!use_inline_certificate_file (ctx, options->cert_file_inline)) + if (!use_inline_certificate_file (ctx, options->cert_file_inline, &my_cert)) msg (M_SSLERR, "Cannot load inline certificate file"); } else #endif { +#ifdef MANAGMENT_EXTERNAL_KEY + if (!use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM, &my_cert)) +#else if (!SSL_CTX_use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM)) +#endif msg (M_SSLERR, "Cannot load certificate file %s", options->cert_file); using_cert_file = true; } } +#ifdef MANAGMENT_EXTERNAL_KEY + if (options->management_flags & MF_EXTERNAL_KEY) + { + ASSERT (my_cert); + if (!use_external_private_key(ctx, my_cert)) + msg (M_SSLERR, "Cannot enable SSL external private key capability"); + } + else +#endif + /* Load Private Key */ if (options->priv_key_file) { @@ -1795,6 +2001,8 @@ init_ssl (const struct options *options) err: ERR_clear_error (); + if (my_cert) + X509_free(my_cert); if (ctx) SSL_CTX_free (ctx); return NULL; diff --git a/syshead.h b/syshead.h index bad5ce0..3b835f7 100644 --- a/syshead.h +++ b/syshead.h @@ -508,6 +508,21 @@ socket_defined (const socket_descriptor_t sd) #define ENABLE_DEF_AUTH #endif +/* + * Enable external private key + */ +#if defined(ENABLE_MANAGEMENT) && defined(USE_SSL) +#define MANAGMENT_EXTERNAL_KEY +#endif + +/* + * MANAGEMENT_IN_EXTRA allows the management interface to + * read multi-line inputs from clients. + */ +#if defined(MANAGEMENT_DEF_AUTH) || defined(MANAGMENT_EXTERNAL_KEY) +#define MANAGEMENT_IN_EXTRA +#endif + /* * Enable packet filter? */ -- cgit v1.2.3 From 7621741b480f93411928c66735d2ee9c7f69de3b Mon Sep 17 00:00:00 2001 From: James Yonan Date: Fri, 10 Dec 2010 21:17:36 +0000 Subject: Minor addition of logging info before and after execution of Windows net commands. Version 2.1.3d git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6712 e7ae566f-a301-0410-adde-c780ea21d3b5 --- tun.c | 2 ++ version.m4 | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tun.c b/tun.c index f6fb505..11c4204 100644 --- a/tun.c +++ b/tun.c @@ -3389,6 +3389,7 @@ ipconfig_register_dns (const struct env_set *es) bool status; const char err[] = "ERROR: Windows ipconfig command failed"; + msg (D_TUNTAP_INFO, "Start net commands..."); netcmd_semaphore_lock (); argv_init (&argv); @@ -3422,6 +3423,7 @@ ipconfig_register_dns (const struct env_set *es) argv_reset(&argv); netcmd_semaphore_release (); + msg (D_TUNTAP_INFO, "End net commands..."); } void diff --git a/version.m4 b/version.m4 index 9af265e..4d84e2b 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3c]) +define(PRODUCT_VERSION,[2.1.3d]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From ae1884c0cbf42c21e54922c150cde44c43200340 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Mon, 13 Dec 2010 09:27:08 +0000 Subject: Misc fixes to r6708. Fixed issue where "signal SIGTERM" entered from the management interface might get subsequently downgraded to a SIGUSR1. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6716 e7ae566f-a301-0410-adde-c780ea21d3b5 --- base64.c | 2 ++ forward.c | 36 ++++++++++++------------------------ init.c | 1 - manage.c | 40 +++++++++++++++++++++++++++------------- manage.h | 14 +++++++++----- sig.c | 8 ++++++++ sig.h | 2 ++ ssl.c | 20 ++++++++++++-------- 8 files changed, 72 insertions(+), 51 deletions(-) diff --git a/base64.c b/base64.c index 8f0fb6c..26ca7d7 100644 --- a/base64.c +++ b/base64.c @@ -50,6 +50,8 @@ base64_encode(const void *data, int size, char **str) int c; const unsigned char *q; + if (size < 0) + return -1; p = s = (char *) malloc(size * 4 / 3 + 4); if (p == NULL) return -1; diff --git a/forward.c b/forward.c index 44ebd0c..5d34472 100644 --- a/forward.c +++ b/forward.c @@ -98,8 +98,7 @@ check_tls_dowork (struct context *c) } else if (tmp_status == TLSMP_KILL) { - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "auth-control-exit"; + register_signal (c, SIGTERM, "auth-control-exit"); } interval_future_trigger (&c->c2.tmp_int, wakeup); @@ -118,15 +117,13 @@ void check_tls_errors_co (struct context *c) { msg (D_STREAM_ERRORS, "Fatal TLS error (check_tls_errors_co), restarting"); - c->sig->signal_received = c->c2.tls_exit_signal; /* SOFT-SIGUSR1 -- TLS error */ - c->sig->signal_text = "tls-error"; + register_signal (c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */ } void check_tls_errors_nco (struct context *c) { - c->sig->signal_received = c->c2.tls_exit_signal; /* SOFT-SIGUSR1 -- TLS error */ - c->sig->signal_text = "tls-error"; + register_signal (c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */ } #endif @@ -287,8 +284,7 @@ check_add_routes_dowork (struct context *c) { if (!tun_standby (c->c1.tuntap)) { - c->sig->signal_received = SIGHUP; - c->sig->signal_text = "ip-fail"; + register_signal (c, SIGHUP, "ip-fail"); c->persist.restart_sleep_seconds = 10; #ifdef WIN32 show_routes (M_INFO|M_NOPREFIX); @@ -310,8 +306,7 @@ void check_inactivity_timeout_dowork (struct context *c) { msg (M_INFO, "Inactivity timeout (--inactive), exiting"); - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "inactive"; + register_signal (c, SIGTERM, "inactive"); } #if P2MP @@ -323,8 +318,7 @@ check_server_poll_timeout_dowork (struct context *c) if (!tls_initial_packet_received (c->c2.tls_multi)) { msg (M_INFO, "Server poll timeout, restarting"); - c->sig->signal_received = SIGUSR1; - c->sig->signal_text = "server_poll"; + register_signal (c, SIGUSR1, "server_poll"); c->persist.restart_sleep_seconds = -1; } } @@ -349,8 +343,7 @@ schedule_exit (struct context *c, const int n_seconds, const int signal) void check_scheduled_exit_dowork (struct context *c) { - c->sig->signal_received = c->c2.scheduled_exit_signal; - c->sig->signal_text = "delayed-exit"; + register_signal (c, c->c2.scheduled_exit_signal, "delayed-exit"); } #endif @@ -677,8 +670,7 @@ read_incoming_link (struct context *c) const struct buffer *fbuf = socket_foreign_protocol_head (c->c2.link_socket); const int sd = socket_foreign_protocol_sd (c->c2.link_socket); port_share_redirect (port_share, fbuf, sd); - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "port-share-redirect"; + register_signal (c, SIGTERM, "port-share-redirect"); } else #endif @@ -686,8 +678,7 @@ read_incoming_link (struct context *c) /* received a disconnect from a connection-oriented protocol */ if (c->options.inetd) { - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "connection-reset-inetd"; + register_signal (c, SIGTERM, "connection-reset-inetd"); msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status); } else @@ -701,8 +692,7 @@ read_incoming_link (struct context *c) else #endif { - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- TCP connection reset */ - c->sig->signal_text = "connection-reset"; + register_signal (c, SIGUSR1, "connection-reset"); /* SOFT-SIGUSR1 -- TCP connection reset */ msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status); } } @@ -834,8 +824,7 @@ process_incoming_link (struct context *c) if (!decrypt_status && link_socket_connection_oriented (c->c2.link_socket)) { /* decryption errors are fatal in TCP mode */ - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- decryption error in TCP mode */ - c->sig->signal_text = "decryption-error"; + register_signal (c, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- decryption error in TCP mode */ msg (D_STREAM_ERRORS, "Fatal decryption error (process_incoming_link), restarting"); goto done; } @@ -947,8 +936,7 @@ read_incoming_tun (struct context *c) /* Was TUN/TAP interface stopped? */ if (tuntap_stop (c->c2.buf.len)) { - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "tun-stop"; + register_signal (c, SIGTERM, "tun-stop"); msg (M_INFO, "TUN/TAP interface has been stopped, exiting"); perf_pop (); return; diff --git a/init.c b/init.c index a46fbde..0de2fcc 100644 --- a/init.c +++ b/init.c @@ -1163,7 +1163,6 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) management_post_tunnel_open (management, tun_local); } #endif - } /* diff --git a/manage.c b/manage.c index 0c99d0f..310a70e 100644 --- a/manage.c +++ b/manage.c @@ -776,12 +776,11 @@ man_hold (struct management *man, const char *cmd) #define IER_RESET 0 #define IER_NEW 1 -#define IER_CONDRESET 2 static void in_extra_reset (struct man_connection *mc, const int mode) { - if (mc && (mc->in_extra_cmd < IEC_STATEFUL_BASE || mode != IER_CONDRESET)) + if (mc) { if (mode != IER_NEW) { @@ -860,7 +859,10 @@ in_extra_dispatch (struct management *man) #endif #ifdef MANAGMENT_EXTERNAL_KEY case IEC_RSA_SIGN: - man->connection.in_extra_cmd = IEC_RSA_SIGN_FINAL; + man->connection.ext_key_state = EKS_READY; + buffer_list_free (man->connection.ext_key_input); + man->connection.ext_key_input = man->connection.in_extra; + man->connection.in_extra = NULL; return; #endif } @@ -1014,10 +1016,11 @@ static void man_rsa_sig (struct management *man) { struct man_connection *mc = &man->connection; - if (mc->in_extra_cmd == IEC_RSA_SIGN_PRE) + if (mc->ext_key_state == EKS_SOLICIT) { - in_extra_reset (&man->connection, IER_NEW); + mc->ext_key_state = EKS_INPUT; mc->in_extra_cmd = IEC_RSA_SIGN; + in_extra_reset (mc, IER_NEW); } else msg (M_CLIENT, "ERROR: The rsa-sig command is not currently available"); @@ -1711,7 +1714,7 @@ man_process_command (struct management *man, const char *line) CLEAR (parms); so = status_open (NULL, 0, -1, &man->persist.vout, 0); #ifdef MANAGEMENT_IN_EXTRA - in_extra_reset (&man->connection, IER_CONDRESET); + in_extra_reset (&man->connection, IER_RESET); #endif if (man_password_needed (man)) @@ -2104,6 +2107,9 @@ man_connection_close (struct management *man) buffer_list_free (mc->out); #ifdef MANAGEMENT_IN_EXTRA in_extra_reset (&man->connection, IER_RESET); +#endif +#ifdef MANAGMENT_EXTERNAL_KEY + buffer_list_free (mc->ext_key_input); #endif man_connection_clear (mc); } @@ -2927,14 +2933,14 @@ management_query_rsa_sig (struct management *man, struct buffer alert_msg = clear_buf(); struct buffer *buf; const bool standalone_disabled_save = man->persist.standalone_disabled; + struct man_connection *mc = &man->connection; if (man_standalone_ok (man)) { man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ man->persist.special_state_msg = NULL; - in_extra_reset (&man->connection, IER_RESET); - man->connection.in_extra_cmd = IEC_RSA_SIGN_PRE; + mc->ext_key_state = EKS_SOLICIT; alert_msg = alloc_buf_gc (strlen(b64_data)+64, &gc); buf_printf (&alert_msg, ">RSA_SIGN:%s", b64_data); @@ -2955,12 +2961,12 @@ management_query_rsa_sig (struct management *man, man_check_for_signals (&signal_received); if (signal_received) goto done; - } while (man->connection.in_extra_cmd != IEC_RSA_SIGN_FINAL); + } while (mc->ext_key_state != EKS_READY); - if (buffer_list_defined(man->connection.in_extra)) + if (buffer_list_defined(mc->ext_key_input)) { - buffer_list_aggregate (man->connection.in_extra, 2000); - buf = buffer_list_peek (man->connection.in_extra); + buffer_list_aggregate (mc->ext_key_input, 2048); + buf = buffer_list_peek (mc->ext_key_input); if (buf && BLEN(buf) > 0) { ret = (char *) malloc(BLEN(buf)+1); @@ -2972,10 +2978,18 @@ management_query_rsa_sig (struct management *man, } done: + if (mc->ext_key_state == EKS_READY && ret) + msg (M_CLIENT, "SUCCESS: rsa-sig command succeeded"); + else if (mc->ext_key_state == EKS_INPUT || mc->ext_key_state == EKS_READY) + msg (M_CLIENT, "ERROR: rsa-sig command failed"); + /* revert state */ man->persist.standalone_disabled = standalone_disabled_save; man->persist.special_state_msg = NULL; - in_extra_reset (&man->connection, IER_RESET); + in_extra_reset (mc, IER_RESET); + mc->ext_key_state = EKS_UNDEF; + buffer_list_free (mc->ext_key_input); + mc->ext_key_input = NULL; gc_free (&gc); return ret; diff --git a/manage.h b/manage.h index 697ddf8..a8f971b 100644 --- a/manage.h +++ b/manage.h @@ -268,11 +268,7 @@ struct man_connection { # define IEC_UNDEF 0 # define IEC_CLIENT_AUTH 1 # define IEC_CLIENT_PF 2 - -# define IEC_STATEFUL_BASE 16 -# define IEC_RSA_SIGN_PRE 16 -# define IEC_RSA_SIGN 17 -# define IEC_RSA_SIGN_FINAL 18 +# define IEC_RSA_SIGN 3 int in_extra_cmd; struct buffer_list *in_extra; #ifdef MANAGEMENT_DEF_AUTH @@ -280,6 +276,14 @@ struct man_connection { unsigned int in_extra_kid; int env_filter_level; #endif +#ifdef MANAGMENT_EXTERNAL_KEY +# define EKS_UNDEF 0 +# define EKS_SOLICIT 1 +# define EKS_INPUT 2 +# define EKS_READY 3 + int ext_key_state; + struct buffer_list *ext_key_input; +#endif #endif struct event_set *es; diff --git a/sig.c b/sig.c index 2704edf..aeac739 100644 --- a/sig.c +++ b/sig.c @@ -375,3 +375,11 @@ process_signal (struct context *c) } return ret; } + +void +register_signal (struct context *c, int sig, const char *text) +{ + if (c->sig->signal_received != SIGTERM) + c->sig->signal_received = sig; + c->sig->signal_text = text; +} diff --git a/sig.h b/sig.h index be87fe4..987efef 100644 --- a/sig.h +++ b/sig.h @@ -64,6 +64,8 @@ void signal_restart_status (const struct signal_info *si); bool process_signal (struct context *c); +void register_signal (struct context *c, int sig, const char *text); + #ifdef ENABLE_OCC void process_explicit_exit_notification_timer_wakeup (struct context *c); #endif diff --git a/ssl.c b/ssl.c index 9ab907c..817ea9d 100644 --- a/ssl.c +++ b/ssl.c @@ -1500,6 +1500,8 @@ use_certificate_file(SSL_CTX *ctx, const char *file, int type, X509 **x509) BIO_free(in); if (x509) *x509 = x; + else if (x) + X509_free (x); return(ret); } @@ -1632,12 +1634,12 @@ use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string, X509 **x509) ret = SSL_CTX_use_certificate(ctx, x); end: - if (x) - X509_free (x); if (in) BIO_free (in); if (x509) *x509 = x; + else if (x) + X509_free (x); return ret; } @@ -1995,17 +1997,19 @@ init_ssl (const struct options *options) msg (M_SSLERR, "Problem with cipher list: %s", options->cipher_list); } + done: ERR_clear_error (); - + if (my_cert) + X509_free(my_cert); return ctx; err: - ERR_clear_error (); - if (my_cert) - X509_free(my_cert); if (ctx) - SSL_CTX_free (ctx); - return NULL; + { + SSL_CTX_free (ctx); + ctx = NULL; + } + goto done; } /* -- cgit v1.2.3 From 9356bae859938c30808aa0d2ee764bdcbb5dbe0d Mon Sep 17 00:00:00 2001 From: James Yonan Date: Wed, 5 Jan 2011 00:50:11 +0000 Subject: Added --x509-track option. Version 2.1.3e git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6780 e7ae566f-a301-0410-adde-c780ea21d3b5 --- errlevel.h | 1 + init.c | 4 ++ manage.c | 7 +++- openvpn.8 | 12 ++++++ options.c | 9 +++++ options.h | 4 ++ ssl.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- ssl.h | 19 ++++++++++ syshead.h | 7 ++++ version.m4 | 2 +- 10 files changed, 186 insertions(+), 4 deletions(-) diff --git a/errlevel.h b/errlevel.h index 75c3194..1d6e866 100644 --- a/errlevel.h +++ b/errlevel.h @@ -104,6 +104,7 @@ #define D_PACKET_TRUNC_ERR LOGLEV(4, 55, 0) /* PACKET_TRUNCATION_CHECK */ #define D_PF_DROPPED LOGLEV(4, 56, 0) /* packet filter dropped a packet */ #define D_MULTI_DROPPED LOGLEV(4, 57, 0) /* show point-to-multipoint packet drops */ +#define D_X509_ATTR LOGLEV(4, 58, 0) /* show x509-track attributes on connection */ #define D_LOG_RW LOGLEV(5, 0, 0) /* Print 'R' or 'W' to stdout for read/write */ diff --git a/init.c b/init.c index 0de2fcc..e694a70 100644 --- a/init.c +++ b/init.c @@ -2049,6 +2049,10 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.client_config_dir_exclusive = options->client_config_dir; #endif +#ifdef ENABLE_X509_TRACK + to.x509_track = options->x509_track; +#endif + /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) { diff --git a/manage.c b/manage.c index 310a70e..eabfb1f 100644 --- a/manage.c +++ b/manage.c @@ -2274,14 +2274,17 @@ env_filter_match (const char *env_str, const int env_filter_level) "bytes_sent=", "bytes_received=" }; - if (env_filter_level >= 1) + + if (env_filter_level >= 2 && !strncmp(env_str, "X509_", 5)) + return true; + else if (env_filter_level >= 1) { size_t i; for (i = 0; i < SIZE(env_names); ++i) { const char *en = env_names[i]; const size_t len = strlen(en); - if (strncmp(env_str, en, len) == 0) + if (!strncmp(env_str, en, len)) return true; } return false; diff --git a/openvpn.8 b/openvpn.8 index 004a30b..3cdc07e 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -4311,6 +4311,18 @@ works in a environment too. .\"********************************************************* .TP +.B --x509-track attribute +Save peer X509 +.B attribute +value in environment for use by plugins and management interface. +Prepend a '+' to +.B attribute +to save values from full cert chain. Values will be encoded +as X509__=. Multiple +.B --x509-track +options can be defined to track multiple attributes. +.\"********************************************************* +.TP .B --ns-cert-type client|server Require that peer certificate was signed with an explicit .B nsCertType diff --git a/options.c b/options.c index 95b6254..2ba18ec 100644 --- a/options.c +++ b/options.c @@ -540,6 +540,8 @@ static const char usage_message[] = " of verification.\n" "--ns-cert-type t: Require that peer certificate was signed with an explicit\n" " nsCertType designation t = 'client' | 'server'.\n" + "--x509-track x : Save peer X509 attribute x in environment for use by\n" + " plugins and management interface.\n" #if OPENSSL_VERSION_NUMBER >= 0x00907000L "--remote-cert-ku v ... : Require that the peer certificate was signed with\n" " explicit key usage, you can specify more than one value.\n" @@ -3651,6 +3653,13 @@ add_option (struct options *options, options->management_flags |= MF_CLIENT_AUTH; } #endif +#ifdef ENABLE_X509_TRACK + else if (streq (p[0], "x509-track") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + x509_track_add (&options->x509_track, p[1], msglevel, &options->gc); + } +#endif #ifdef MANAGEMENT_PF else if (streq (p[0], "management-client-pf")) { diff --git a/options.h b/options.h index fc5db58..4a56701 100644 --- a/options.h +++ b/options.h @@ -532,6 +532,10 @@ struct options #endif /* USE_SSL */ #endif /* USE_CRYPTO */ +#ifdef ENABLE_X509_TRACK + const struct x509_track *x509_track; +#endif + /* special state parms */ int foreign_option_index; diff --git a/ssl.c b/ssl.c index 817ea9d..f1f0688 100644 --- a/ssl.c +++ b/ssl.c @@ -518,6 +518,99 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, int } } +#ifdef ENABLE_X509_TRACK +/* + * setenv_x509_track function -- save X509 fields to environment, + * using the naming convention: + * + * X509_{cert_depth}_{name}={value} + * + * This function differs from setenv_x509 below in the following ways: + * + * (1) Only explicitly named attributes in xt are saved, per usage + * of --x509-track program options. + * (2) Only the level 0 cert info is saved unless the XT_FULL_CHAIN + * flag is set in xt->flags (corresponds with prepending a '+' + * to the name when specified by --x509-track program option). + * (3) This function supports both X509 subject name fields as + * well as X509 V3 extensions. + */ + +/* worker method for setenv_x509_track */ +static void +do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) +{ + char *name_expand; + size_t name_expand_size; + + string_mod (value, CC_ANY, CC_CRLF, '?'); + msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); + name_expand_size = 64 + strlen (name); + name_expand = (char *) malloc (name_expand_size); + check_malloc_return (name_expand); + openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name); + setenv_str (es, name_expand, value); + free (name_expand); +} + +static void +setenv_x509_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509) +{ + X509_NAME *x509_name = X509_get_subject_name (x509); + const char nullc = '\0'; + int i; + + while (xt) + { + if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) + { + i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); + if (i >= 0) + { + X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); + if (ent) + { + ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); + unsigned char *buf; + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + if (ASN1_STRING_to_UTF8 (&buf, val) > 0) + { + do_setenv_x509(es, xt->name, (char *)buf, depth); + OPENSSL_free (buf); + } + } + } + else + { + i = X509_get_ext_by_NID(x509, xt->nid, -1); + if (i >= 0) + { + X509_EXTENSION *ext = X509_get_ext(x509, i); + if (ext) + { + BIO *bio = BIO_new(BIO_s_mem()); + if (bio) + { + if (X509V3_EXT_print(bio, ext, 0, 0)) + { + if (BIO_write(bio, &nullc, 1) == 1) + { + char *str; + BIO_get_mem_data(bio, &str); + do_setenv_x509(es, xt->name, str, depth); + } + } + BIO_free(bio); + } + } + } + } + } + xt = xt->next; + } +} +#endif + /* * Save X509 fields to environment, using the naming convention: * @@ -751,7 +844,12 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) } /* Save X509 fields in environment */ - setenv_x509 (opt->es, ctx->error_depth, X509_get_subject_name (ctx->current_cert)); +#ifdef ENABLE_X509_TRACK + if (opt->x509_track) + setenv_x509_track (opt->x509_track, opt->es, ctx->error_depth, ctx->current_cert); + else +#endif + setenv_x509 (opt->es, ctx->error_depth, X509_get_subject_name (ctx->current_cert)); /* enforce character class restrictions in X509 name */ string_mod_sslname (subject, X509_NAME_CHAR_CLASS, opt->ssl_flags); @@ -1066,6 +1164,31 @@ tls_lock_username (struct tls_multi *multi, const char *username) return true; } +#ifdef ENABLE_X509_TRACK + +void +x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) +{ + struct x509_track *xt; + ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc); + if (*name == '+') + { + xt->flags |= XT_FULL_CHAIN; + ++name; + } + xt->name = name; + xt->nid = OBJ_txt2nid(name); + if (xt->nid != NID_undef) + { + xt->next = *ll_head; + *ll_head = xt; + } + else + msg(msglevel, "x509_track: no such attribute '%s'", name); +} + +#endif + #ifdef ENABLE_DEF_AUTH /* key_state_test_auth_control_file return values, NOTE: acf_merge indexing depends on these values */ diff --git a/ssl.h b/ssl.h index 4373a80..eb059cc 100644 --- a/ssl.h +++ b/ssl.h @@ -402,6 +402,21 @@ struct key_state #endif }; +#ifdef ENABLE_X509_TRACK + +struct x509_track +{ + const struct x509_track *next; + const char *name; +# define XT_FULL_CHAIN (1<<0) + unsigned int flags; + int nid; +}; + +void x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc); + +#endif + /* * Our const options, obtained directly or derived from * command line options. @@ -494,6 +509,10 @@ struct tls_options struct man_def_auth_context *mda_context; #endif +#ifdef ENABLE_X509_TRACK + const struct x509_track *x509_track; +#endif + /* --gremlin bits */ int gremlin; }; diff --git a/syshead.h b/syshead.h index 3b835f7..4e6ef08 100644 --- a/syshead.h +++ b/syshead.h @@ -607,6 +607,13 @@ socket_defined (const socket_descriptor_t sd) #define ENABLE_PKCS11 #endif +/* + * Enable x509-track feature? + */ +#if defined(USE_CRYPTO) && defined(USE_SSL) +#define ENABLE_X509_TRACK +#endif + /* * Is poll available on this platform? */ diff --git a/version.m4 b/version.m4 index 4d84e2b..44d9190 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3d]) +define(PRODUCT_VERSION,[2.1.3e]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 15be3202b279abc431597db5d11e826eaf1c1bb6 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Mon, 10 Jan 2011 19:13:02 +0000 Subject: * added --management-up-down option to allow management interface to be notified of tunnel up/down events. * pulled --ip-win32 options will be suppressed on the client if --route-nopull option is specified. Version 2.1.3f git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6813 e7ae566f-a301-0410-adde-c780ea21d3b5 --- init.c | 17 +++++++++++++---- manage.c | 43 +++++++++++++++++++++++++++---------------- manage.h | 3 +++ openvpn.8 | 5 +++++ options.c | 6 ++++++ version.m4 | 2 +- 6 files changed, 55 insertions(+), 21 deletions(-) diff --git a/init.c b/init.c index e694a70..7f072ae 100644 --- a/init.c +++ b/init.c @@ -1177,7 +1177,14 @@ do_route (const struct options *options, struct env_set *es) { if (!options->route_noexec && route_list) - add_routes (route_list, tt, ROUTE_OPTION_FLAGS (options), es); + { + add_routes (route_list, tt, ROUTE_OPTION_FLAGS (options), es); + setenv_int (es, "redirect_gateway", route_list->did_redirect_default_gateway); + } +#ifdef ENABLE_MANAGEMENT + if (management) + management_up_down (management, "UP", es); +#endif if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP)) { @@ -1385,7 +1392,10 @@ do_close_tun (struct context *c, bool force) #ifdef ENABLE_MANAGEMENT /* tell management layer we are about to close the TUN/TAP device */ if (management) - management_pre_tunnel_close (management); + { + management_pre_tunnel_close (management); + management_up_down (management, "DOWN", c->c2.es); + } #endif /* delete any routes we added */ @@ -1527,7 +1537,6 @@ pull_permission_mask (const struct context *c) unsigned int flags = OPT_P_UP | OPT_P_ROUTE_EXTRAS - | OPT_P_IPWIN32 | OPT_P_SOCKBUF | OPT_P_SOCKFLAGS | OPT_P_SETENV @@ -1541,7 +1550,7 @@ pull_permission_mask (const struct context *c) | OPT_P_PULL_MODE; if (!c->options.route_nopull) - flags |= OPT_P_ROUTE; + flags |= (OPT_P_ROUTE | OPT_P_IPWIN32); return flags; } diff --git a/manage.c b/manage.c index eabfb1f..e8f67cd 100644 --- a/manage.c +++ b/manage.c @@ -2252,8 +2252,6 @@ management_set_state (struct management *man, } } -#ifdef MANAGEMENT_DEF_AUTH - static bool env_filter_match (const char *env_str, const int env_filter_level) { @@ -2275,9 +2273,11 @@ env_filter_match (const char *env_str, const int env_filter_level) "bytes_received=" }; - if (env_filter_level >= 2 && !strncmp(env_str, "X509_", 5)) + if (env_filter_level == 0) return true; - else if (env_filter_level >= 1) + else if (env_filter_level <= 1 && !strncmp(env_str, "X509_", 5)) + return true; + else if (env_filter_level <= 2) { size_t i; for (i = 0; i < SIZE(env_names); ++i) @@ -2289,12 +2289,11 @@ env_filter_match (const char *env_str, const int env_filter_level) } return false; } - else - return true; + return false; } static void -man_output_env (const struct env_set *es, const bool tail, const int env_filter_level) +man_output_env (const struct env_set *es, const bool tail, const int env_filter_level, const char *prefix) { if (es) { @@ -2302,15 +2301,15 @@ man_output_env (const struct env_set *es, const bool tail, const int env_filter_ for (e = es->list; e != NULL; e = e->next) { if (e->string && (!env_filter_level || env_filter_match(e->string, env_filter_level))) - msg (M_CLIENT, ">CLIENT:ENV,%s", e->string); + msg (M_CLIENT, ">%s:ENV,%s", prefix, e->string); } } if (tail) - msg (M_CLIENT, ">CLIENT:ENV,END"); + msg (M_CLIENT, ">%s:ENV,END", prefix); } static void -man_output_extra_env (struct management *man) +man_output_extra_env (struct management *man, const char *prefix) { struct gc_arena gc = gc_new (); struct env_set *es = env_set_create (&gc); @@ -2319,10 +2318,22 @@ man_output_extra_env (struct management *man) const int nclients = (*man->persist.callback.n_clients) (man->persist.callback.arg); setenv_int (es, "n_clients", nclients); } - man_output_env (es, false, man->connection.env_filter_level); + man_output_env (es, false, man->connection.env_filter_level, prefix); gc_free (&gc); } +void +management_up_down(struct management *man, const char *updown, const struct env_set *es) +{ + if (man->settings.flags & MF_UP_DOWN) + { + msg (M_CLIENT, ">UPDOWN:%s", updown); + man_output_env (es, true, 0, "UPDOWN"); + } +} + +#ifdef MANAGEMENT_DEF_AUTH + static bool validate_peer_info_line(const char *line) { @@ -2387,9 +2398,9 @@ management_notify_client_needing_auth (struct management *management, if (mdac->flags & DAF_CONNECTION_ESTABLISHED) mode = "REAUTH"; msg (M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id); - man_output_extra_env (management); + man_output_extra_env (management, "CLIENT"); man_output_peer_info_env(management, mdac); - man_output_env (es, true, management->connection.env_filter_level); + man_output_env (es, true, management->connection.env_filter_level, "CLIENT"); mdac->flags |= DAF_INITIAL_AUTH; } } @@ -2401,8 +2412,8 @@ management_connection_established (struct management *management, { mdac->flags |= DAF_CONNECTION_ESTABLISHED; msg (M_CLIENT, ">CLIENT:ESTABLISHED,%lu", mdac->cid); - man_output_extra_env (management); - man_output_env (es, true, management->connection.env_filter_level); + man_output_extra_env (management, "CLIENT"); + man_output_env (es, true, management->connection.env_filter_level, "CLIENT"); } void @@ -2413,7 +2424,7 @@ management_notify_client_close (struct management *management, if ((mdac->flags & DAF_INITIAL_AUTH) && !(mdac->flags & DAF_CONNECTION_CLOSED)) { msg (M_CLIENT, ">CLIENT:DISCONNECT,%lu", mdac->cid); - man_output_env (es, true, management->connection.env_filter_level); + man_output_env (es, true, management->connection.env_filter_level, "CLIENT"); mdac->flags |= DAF_CONNECTION_CLOSED; } } diff --git a/manage.h b/manage.h index a8f971b..c884caf 100644 --- a/manage.h +++ b/manage.h @@ -332,6 +332,7 @@ struct management *management_init (void); #ifdef MANAGMENT_EXTERNAL_KEY # define MF_EXTERNAL_KEY (1<<9) #endif +#define MF_UP_DOWN (1<<10) bool management_open (struct management *man, const char *addr, @@ -372,6 +373,8 @@ bool management_hold (struct management *man); void management_event_loop_n_seconds (struct management *man, int sec); +void management_up_down(struct management *man, const char *updown, const struct env_set *es); + #ifdef MANAGEMENT_DEF_AUTH void management_notify_client_needing_auth (struct management *management, const unsigned int auth_id, diff --git a/openvpn.8 b/openvpn.8 index 3cdc07e..164b58e 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -2367,6 +2367,11 @@ lines of log file history for usage by the management channel. .\"********************************************************* .TP +.B --management-up-down +Report tunnel up/down events to management interface. +.B +.\"********************************************************* +.TP .B --management-client-auth Gives management interface client the responsibility to authenticate clients after their client certificate diff --git a/options.c b/options.c index 2ba18ec..a4b2d49 100644 --- a/options.c +++ b/options.c @@ -341,6 +341,7 @@ static const char usage_message[] = "--management-signal : Issue SIGUSR1 when management disconnect event occurs.\n" "--management-forget-disconnect : Forget passwords when management disconnect\n" " event occurs.\n" + "--management-up-down : Report tunnel up/down events to management interface.\n" "--management-log-cache n : Cache n lines of log file history for usage\n" " by the management channel.\n" #if UNIX_SOCK_SUPPORT @@ -3632,6 +3633,11 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_FORGET_DISCONNECT; } + else if (streq (p[0], "management-up-down")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->management_flags |= MF_UP_DOWN; + } else if (streq (p[0], "management-client")) { VERIFY_PERMISSION (OPT_P_GENERAL); diff --git a/version.m4 b/version.m4 index 44d9190..6d51fb6 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3e]) +define(PRODUCT_VERSION,[2.1.3f]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From c65e30f520398d3b031a663978eb7668315add69 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Tue, 18 Jan 2011 16:12:13 +0000 Subject: Fixed minor compile issue triggered on builds where MANAGEMENT_DEF_AUTH is not enabled. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6830 e7ae566f-a301-0410-adde-c780ea21d3b5 --- manage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manage.h b/manage.h index c884caf..18b1564 100644 --- a/manage.h +++ b/manage.h @@ -274,7 +274,6 @@ struct man_connection { #ifdef MANAGEMENT_DEF_AUTH unsigned long in_extra_cid; unsigned int in_extra_kid; - int env_filter_level; #endif #ifdef MANAGMENT_EXTERNAL_KEY # define EKS_UNDEF 0 @@ -286,6 +285,7 @@ struct man_connection { #endif #endif struct event_set *es; + int env_filter_level; bool state_realtime; bool log_realtime; -- cgit v1.2.3 From 6a8ea97069b8edb4a50744faae3bab8ecd931840 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Mon, 14 Feb 2011 03:46:37 +0000 Subject: Implemented get_default_gateway_mac_addr for Mac OS X (previously, was only defined for Windows and Linux). This enables OS X to report the MAC address of the default gateway to the server for ID purposes when client-side --push-peer-info option is specified. Also, minor fix to OS X get_default_gateway function: * include net/route.h directly rather than selectively paste stuff from it into route.c git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6925 e7ae566f-a301-0410-adde-c780ea21d3b5 --- init.c | 21 ++++++++ route.c | 161 +++++++++++++++++++++++++++++++++++++++---------------------- version.m4 | 2 +- 3 files changed, 125 insertions(+), 59 deletions(-) diff --git a/init.c b/init.c index 7f072ae..70357e1 100644 --- a/init.c +++ b/init.c @@ -600,6 +600,27 @@ init_static (void) return false; #endif +#ifdef TEST_GET_DEFAULT_GATEWAY + { + struct gc_arena gc = gc_new (); + in_addr_t addr; + char macaddr[6]; + + if (get_default_gateway(&addr, NULL)) + msg (M_INFO, "GW %s", print_in_addr_t(addr, 0, &gc)); + else + msg (M_INFO, "GDG ERROR"); + + if (get_default_gateway_mac_addr(macaddr)) + msg (M_INFO, "MAC %s", format_hex_ex (macaddr, 6, 0, 1, ":", &gc)); + else + msg (M_INFO, "GDGMA ERROR"); + + gc_free (&gc); + return false; + } +#endif + #ifdef GEN_PATH_TEST { struct gc_arena gc = gc_new (); diff --git a/route.c b/route.c index 20f62d5..711f7f9 100644 --- a/route.c +++ b/route.c @@ -1791,70 +1791,26 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask) #include #include #include +#include +#include -/* all of this is taken from in Darwin */ -#define RTA_DST 0x1 -#define RTA_GATEWAY 0x2 -#define RTA_NETMASK 0x4 - -#define RTM_GET 0x4 -#define RTM_VERSION 5 - -#define RTF_UP 0x1 -#define RTF_GATEWAY 0x2 - -/* - * These numbers are used by reliable protocols for determining - * retransmission behavior and are included in the routing structure. - */ -struct rt_metrics { - u_long rmx_locks; /* Kernel must leave these values alone */ - u_long rmx_mtu; /* MTU for this path */ - u_long rmx_hopcount; /* max hops expected */ - u_long rmx_expire; /* lifetime for route, e.g. redirect */ - u_long rmx_recvpipe; /* inbound delay-bandwidth product */ - u_long rmx_sendpipe; /* outbound delay-bandwidth product */ - u_long rmx_ssthresh; /* outbound gateway buffer limit */ - u_long rmx_rtt; /* estimated round trip time */ - u_long rmx_rttvar; /* estimated rtt variance */ - u_long rmx_pksent; /* packets sent using this route */ - u_long rmx_filler[4]; /* will be used for T/TCP later */ -}; - -/* - * Structures for routing messages. - */ -struct rt_msghdr { - u_short rtm_msglen; /* to skip over non-understood messages */ - u_char rtm_version; /* future binary compatibility */ - u_char rtm_type; /* message type */ - u_short rtm_index; /* index for associated ifp */ - int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ - int rtm_addrs; /* bitmask identifying sockaddrs in msg */ - pid_t rtm_pid; /* identify sender */ - int rtm_seq; /* for sender to identify action */ - int rtm_errno; /* why failed */ - int rtm_use; /* from rtentry */ - u_long rtm_inits; /* which metrics we are initializing */ - struct rt_metrics rtm_rmx; /* metrics themselves */ -}; - -struct { +struct rtmsg { struct rt_msghdr m_rtm; char m_space[512]; -} m_rtmsg; +}; #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) -bool -get_default_gateway (in_addr_t *ret, in_addr_t *netmask) +static bool +get_default_gateway_ex (in_addr_t *ret, in_addr_t *netmask, char **ifname) { struct gc_arena gc = gc_new (); + struct rtmsg m_rtmsg; int s, seq, l, pid, rtm_addrs, i; struct sockaddr so_dst, so_mask; char *cp = m_rtmsg.m_space; - struct sockaddr *gate = NULL, *sa; + struct sockaddr *gate = NULL, *ifp = NULL, *sa; struct rt_msghdr *rtm_aux; #define NEXTADDR(w, u) \ @@ -1868,8 +1824,9 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask) pid = getpid(); seq = 0; - rtm_addrs = RTA_DST | RTA_NETMASK; + rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP; + bzero(&m_rtmsg, sizeof(m_rtmsg)); bzero(&so_dst, sizeof(so_dst)); bzero(&so_mask, sizeof(so_mask)); bzero(&rtm, sizeof(struct rt_msghdr)); @@ -1911,11 +1868,16 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask) cp = ((char *)(rtm_aux + 1)); if (rtm_aux->rtm_addrs) { for (i = 1; i; i <<= 1) - if (i & rtm_aux->rtm_addrs) { - sa = (struct sockaddr *)cp; - if (i == RTA_GATEWAY ) - gate = sa; - ADVANCE(cp, sa); + { + if (i & rtm_aux->rtm_addrs) + { + sa = (struct sockaddr *)cp; + if (i == RTA_GATEWAY ) + gate = sa; + else if (i == RTA_IFP) + ifp = sa; + ADVANCE(cp, sa); + } } } else @@ -1938,6 +1900,16 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask) *netmask = 0xFFFFFF00; // FIXME -- get the real netmask of the adapter containing the default gateway } + if (ifp && ifname) + { + struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp; + char *name = malloc(adl->sdl_nlen+1); + check_malloc_return(name); + memcpy(name, adl->sdl_data, adl->sdl_nlen); + name[adl->sdl_nlen] = '\0'; + *ifname = name; + } + gc_free (&gc); return true; } @@ -1948,6 +1920,12 @@ get_default_gateway (in_addr_t *ret, in_addr_t *netmask) } } +bool +get_default_gateway (in_addr_t *ret, in_addr_t *netmask) +{ + return get_default_gateway_ex(ret, netmask, NULL); +} + #elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) #include @@ -2353,6 +2331,73 @@ get_default_gateway_mac_addr (unsigned char *macaddr) return false; } +#elif defined(TARGET_DARWIN) + +bool +get_default_gateway_mac_addr (unsigned char *macaddr) +{ +# define max(a,b) ((a) > (b) ? (a) : (b)) + struct gc_arena gc = gc_new (); + struct ifconf ifc; + struct ifreq *ifr; + char *buffer, *cp; + bool status = false; + in_addr_t gw = 0; + char *ifname = NULL; + int sockfd = -1; + const int bufsize = 4096; + + if (!get_default_gateway_ex (&gw, NULL, &ifname)) /* get interface name of default gateway */ + { + msg (M_WARN, "GDGMA: get_default_gateway_ex failed"); + goto done; + } + + if (!ifname) + { + msg (M_WARN, "GDGMA: cannot get default gateway ifname"); + goto done; + } + + buffer = (char *) gc_malloc (bufsize, false, &gc); + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + msg (M_WARN, "GDGMA: socket failed"); + goto done; + } + + ifc.ifc_len = bufsize; + ifc.ifc_buf = buffer; + + if (ioctl(sockfd, SIOCGIFCONF, (char *)&ifc) < 0) + { + msg (M_WARN, "GDGMA: ioctl failed"); + goto done; + } + + for (cp = buffer; cp < buffer + bufsize; ) + { + ifr = (struct ifreq *)cp; + if (ifr->ifr_addr.sa_family == AF_LINK && !strncmp(ifr->ifr_name, ifname, IFNAMSIZ)) + { + struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; + memcpy(macaddr, LLADDR(sdl), 6); + status = true; + } + cp += sizeof(ifr->ifr_name) + max(sizeof(ifr->ifr_addr), ifr->ifr_addr.sa_len); + } + + done: + if (sockfd >= 0) + close (sockfd); + free (ifname); + gc_free (&gc); + return status; +# undef max +} + #else bool diff --git a/version.m4 b/version.m4 index 6d51fb6..2ca0739 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3f]) +define(PRODUCT_VERSION,[2.1.3g]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 3f7c03a23e097f69b716ea79a79848e5ba0a4303 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Mon, 14 Feb 2011 05:20:23 +0000 Subject: Fixes to r6925. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6927 e7ae566f-a301-0410-adde-c780ea21d3b5 --- route.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/route.c b/route.c index 711f7f9..c3e4acf 100644 --- a/route.c +++ b/route.c @@ -1800,7 +1800,7 @@ struct rtmsg { }; #define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t)) static bool get_default_gateway_ex (in_addr_t *ret, in_addr_t *netmask, char **ifname) @@ -2359,7 +2359,7 @@ get_default_gateway_mac_addr (unsigned char *macaddr) goto done; } - buffer = (char *) gc_malloc (bufsize, false, &gc); + buffer = (char *) gc_malloc (bufsize, true, &gc); sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) @@ -2377,7 +2377,7 @@ get_default_gateway_mac_addr (unsigned char *macaddr) goto done; } - for (cp = buffer; cp < buffer + bufsize; ) + for (cp = buffer; cp <= buffer + bufsize - sizeof(struct ifreq); ) { ifr = (struct ifreq *)cp; if (ifr->ifr_addr.sa_family == AF_LINK && !strncmp(ifr->ifr_name, ifname, IFNAMSIZ)) -- cgit v1.2.3 From 7ae5fb20d7dc52641ef853b896dffc0f283d16d2 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Mon, 14 Feb 2011 22:03:44 +0000 Subject: Properly handle certificate serial numbers > 32 bits. Version 2.1.3h git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6931 e7ae566f-a301-0410-adde-c780ea21d3b5 --- ssl.c | 14 +++++++++++--- version.m4 | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ssl.c b/ssl.c index f1f0688..16e4c09 100644 --- a/ssl.c +++ b/ssl.c @@ -912,11 +912,19 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) setenv_str (opt->es, envname, common_name); #endif - /* export serial number as environmental variable */ + /* export serial number as environmental variable, + use bignum in case serial number is large */ { - const int serial = (int) ASN1_INTEGER_get (X509_get_serialNumber (ctx->current_cert)); + ASN1_INTEGER *asn1_i; + BIGNUM *bignum; + char *dec; + asn1_i = X509_get_serialNumber(ctx->current_cert); + bignum = ASN1_INTEGER_to_BN(asn1_i, NULL); + dec = BN_bn2dec(bignum); openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", ctx->error_depth); - setenv_int (opt->es, envname, serial); + setenv_str (opt->es, envname, dec); + BN_free(bignum); + OPENSSL_free(dec); } /* export current untrusted IP */ diff --git a/version.m4 b/version.m4 index 2ca0739..72d6ea2 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3g]) +define(PRODUCT_VERSION,[2.1.3h]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 581bef87088ed2c559f66552088166903cf0098d Mon Sep 17 00:00:00 2001 From: James Yonan Date: Fri, 18 Feb 2011 17:48:25 +0000 Subject: Added "client-nat" option for stateless, one-to-one NAT on the client side. Version 2.1.3i. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6944 e7ae566f-a301-0410-adde-c780ea21d3b5 --- Makefile.am | 2 + clinat.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ clinat.h | 65 +++++++++++++++ errlevel.h | 1 + forward.c | 12 ++- forward.h | 1 + multi.c | 3 + openvpn.8 | 36 ++++++++- openvpn.h | 3 + options.c | 49 +++++++++++ options.h | 13 +++ proto.h | 37 ++++++--- push.c | 15 +++- syshead.h | 5 ++ version.m4 | 2 +- 15 files changed, 490 insertions(+), 17 deletions(-) create mode 100644 clinat.c create mode 100644 clinat.h diff --git a/Makefile.am b/Makefile.am index 24649cd..97e0971 100644 --- a/Makefile.am +++ b/Makefile.am @@ -78,7 +78,9 @@ openvpn_SOURCES = \ basic.h \ buffer.c buffer.h \ circ_list.h \ + clinat.c clinat.h \ common.h \ + config-win32.h \ crypto.c crypto.h \ dhcp.c dhcp.h \ errlevel.h \ diff --git a/clinat.c b/clinat.c new file mode 100644 index 0000000..8e85e22 --- /dev/null +++ b/clinat.c @@ -0,0 +1,263 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "syshead.h" + +#if defined(ENABLE_CLIENT_NAT) + +#include "clinat.h" +#include "proto.h" +#include "socket.h" +#include "memdbg.h" + +static bool +add_entry(struct client_nat_option_list *dest, + const struct client_nat_entry *e) +{ + if (dest->n >= MAX_CLIENT_NAT) + { + msg (M_WARN, "WARNING: client-nat table overflow (max %d entries)", MAX_CLIENT_NAT); + return false; + } + else + { + dest->entries[dest->n++] = *e; + return true; + } +} + +void +print_client_nat_list(const struct client_nat_option_list *list, int msglevel) +{ + struct gc_arena gc = gc_new (); + int i; + + msg (msglevel, "*** CNAT list"); + if (list) + { + for (i = 0; i < list->n; ++i) + { + const struct client_nat_entry *e = &list->entries[i]; + msg (msglevel, " CNAT[%d] t=%d %s/%s/%s", + i, + e->type, + print_in_addr_t (e->network, IA_NET_ORDER, &gc), + print_in_addr_t (e->netmask, IA_NET_ORDER, &gc), + print_in_addr_t (e->foreign_network, IA_NET_ORDER, &gc)); + } + } + gc_free (&gc); +} + +struct client_nat_option_list * +new_client_nat_list (struct gc_arena *gc) +{ + struct client_nat_option_list *ret; + ALLOC_OBJ_CLEAR_GC (ret, struct client_nat_option_list, gc); + return ret; +} + +struct client_nat_option_list * +clone_client_nat_option_list (const struct client_nat_option_list *src, struct gc_arena *gc) +{ + struct client_nat_option_list *ret; + ALLOC_OBJ_GC (ret, struct client_nat_option_list, gc); + *ret = *src; + return ret; +} + +void +copy_client_nat_option_list (struct client_nat_option_list *dest, + const struct client_nat_option_list *src) +{ + int i; + for (i = 0; i < src->n; ++i) + { + if (!add_entry(dest, &src->entries[i])) + break; + } +} + +void +add_client_nat_to_option_list (struct client_nat_option_list *dest, + const char *type, + const char *network, + const char *netmask, + const char *foreign_network, + int msglevel) +{ + struct client_nat_entry e; + bool ok; + + if (!strcmp(type, "snat")) + e.type = CN_SNAT; + else if (!strcmp(type, "dnat")) + e.type = CN_DNAT; + else + { + msg(msglevel, "client-nat: type must be 'snat' or 'dnat'"); + return; + } + + e.network = getaddr(0, network, 0, &ok, NULL); + if (!ok) + { + msg(msglevel, "client-nat: bad network: %s", network); + return; + } + e.netmask = getaddr(0, netmask, 0, &ok, NULL); + if (!ok) + { + msg(msglevel, "client-nat: bad netmask: %s", netmask); + return; + } + e.foreign_network = getaddr(0, foreign_network, 0, &ok, NULL); + if (!ok) + { + msg(msglevel, "client-nat: bad foreign network: %s", foreign_network); + return; + } + + add_entry(dest, &e); +} + +#if 0 +static void +print_checksum (struct openvpn_iphdr *iph, const char *prefix) +{ + uint16_t *sptr; + unsigned int sum = 0; + int i = 0; + for (sptr = (uint16_t *)iph; (uint8_t *)sptr < (uint8_t *)iph + sizeof(struct openvpn_iphdr); sptr++) + { + i += 1; + sum += *sptr; + } + msg (M_INFO, "** CKSUM[%d] %s %08x", i, prefix, sum); +} +#endif + +static void +print_pkt (struct openvpn_iphdr *iph, const char *prefix, const int direction, const int msglevel) +{ + struct gc_arena gc = gc_new (); + + char *dirstr = "???"; + if (direction == CN_OUTGOING) + dirstr = "OUT"; + else if (direction == CN_INCOMING) + dirstr = "IN"; + + msg(msglevel, "** CNAT %s %s %s -> %s", + dirstr, + prefix, + print_in_addr_t (iph->saddr, IA_NET_ORDER, &gc), + print_in_addr_t (iph->daddr, IA_NET_ORDER, &gc)); + + gc_free (&gc); +} + +void +client_nat_transform (const struct client_nat_option_list *list, + struct buffer *ipbuf, + const int direction) +{ + struct ip_tcp_udp_hdr *h = (struct ip_tcp_udp_hdr *) BPTR (ipbuf); + int i; + uint32_t addr, *addr_ptr; + const uint32_t *from, *to; + int accumulate = 0; + unsigned int amask; + unsigned int alog = 0; + + if (check_debug_level (D_CLIENT_NAT)) + print_pkt (&h->ip, "BEFORE", direction, D_CLIENT_NAT); + + for (i = 0; i < list->n; ++i) + { + const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */ + if (e->type ^ direction) + { + addr = *(addr_ptr = &h->ip.daddr); + amask = 2; + } + else + { + addr = *(addr_ptr = &h->ip.saddr); + amask = 1; + } + if (direction) + { + from = &e->foreign_network; + to = &e->network; + } + else + { + from = &e->network; + to = &e->foreign_network; + } + + if (((addr & e->netmask) == *from) && !(amask & alog)) + { + /* pre-adjust IP checksum */ + ADD_CHECKSUM_32(accumulate, addr); + + /* do NAT transform */ + addr = (addr & ~e->netmask) | *to; + + /* post-adjust IP checksum */ + SUB_CHECKSUM_32(accumulate, addr); + + /* write the modified address to packet */ + *addr_ptr = addr; + + /* mark as modified */ + alog |= amask; + } + } + if (alog) + { + if (check_debug_level (D_CLIENT_NAT)) + print_pkt (&h->ip, "AFTER", direction, D_CLIENT_NAT); + + ADJUST_CHECKSUM(accumulate, h->ip.check); + + if (h->ip.protocol == OPENVPN_IPPROTO_TCP) + { + if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_tcphdr)) + { + ADJUST_CHECKSUM(accumulate, h->u.tcp.check); + } + } + else if (h->ip.protocol == OPENVPN_IPPROTO_UDP) + { + if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr)) + { + ADJUST_CHECKSUM(accumulate, h->u.udp.check); + } + } + } +} + +#endif diff --git a/clinat.h b/clinat.h new file mode 100644 index 0000000..d55a727 --- /dev/null +++ b/clinat.h @@ -0,0 +1,65 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(CLINAT_H) && defined(ENABLE_CLIENT_NAT) +#define CLINAT_H + +#include "buffer.h" + +#define MAX_CLIENT_NAT 64 + +#define CN_OUTGOING 0 +#define CN_INCOMING 1 + +struct client_nat_entry { +# define CN_SNAT 0 +# define CN_DNAT 1 + int type; + in_addr_t network; + in_addr_t netmask; + in_addr_t foreign_network; +}; + +struct client_nat_option_list { + int n; + struct client_nat_entry entries[MAX_CLIENT_NAT]; +}; + +struct client_nat_option_list *new_client_nat_list (struct gc_arena *gc); +struct client_nat_option_list *clone_client_nat_option_list (const struct client_nat_option_list *src, struct gc_arena *gc); +void copy_client_nat_option_list (struct client_nat_option_list *dest, const struct client_nat_option_list *src); +void print_client_nat_list(const struct client_nat_option_list *list, int msglevel); + +void add_client_nat_to_option_list (struct client_nat_option_list *dest, + const char *type, + const char *network, + const char *netmask, + const char *foreign_network, + int msglevel); + +void client_nat_transform (const struct client_nat_option_list *list, + struct buffer *ipbuf, + const int direction); + +#endif diff --git a/errlevel.h b/errlevel.h index 1d6e866..a47edac 100644 --- a/errlevel.h +++ b/errlevel.h @@ -111,6 +111,7 @@ #define D_LINK_RW LOGLEV(6, 60, M_DEBUG) /* show TCP/UDP reads/writes (terse) */ #define D_TUN_RW LOGLEV(6, 60, M_DEBUG) /* show TUN/TAP reads/writes */ #define D_TAP_WIN32_DEBUG LOGLEV(6, 60, M_DEBUG) /* show TAP-Win32 driver debug info */ +#define D_CLIENT_NAT LOGLEV(6, 60, M_DEBUG) /* show client NAT debug info */ #define D_SHOW_KEYS LOGLEV(7, 70, M_DEBUG) /* show data channel encryption keys */ #define D_SHOW_KEY_SOURCE LOGLEV(7, 70, M_DEBUG) /* show data channel key source entropy */ diff --git a/forward.c b/forward.c index 5d34472..ce0a7c4 100644 --- a/forward.c +++ b/forward.c @@ -977,7 +977,7 @@ process_incoming_tun (struct context *c) * The --passtos and --mssfix options require * us to examine the IPv4 header. */ - process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX, &c->c2.buf); + process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf); #ifdef PACKET_TRUNCATION_CHECK /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ @@ -1035,6 +1035,14 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf) if (flags & PIPV4_MSSFIX) mss_fixup (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); +#ifdef ENABLE_CLIENT_NAT + /* possibly do NAT on packet */ + if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat) + { + const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING; + client_nat_transform (c->options.client_nat, &ipbuf, direction); + } +#endif /* possibly extract a DHCP router message */ if (flags & PIPV4_EXTRACT_DHCP_ROUTER) { @@ -1196,7 +1204,7 @@ process_outgoing_tun (struct context *c) * The --mssfix option requires * us to examine the IPv4 header. */ - process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_OUTGOING, &c->c2.to_tun); + process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun); if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame)) { diff --git a/forward.h b/forward.h index 17cc928..76d8b9e 100644 --- a/forward.h +++ b/forward.h @@ -76,6 +76,7 @@ bool send_control_channel_string (struct context *c, const char *str, int msglev #define PIPV4_MSSFIX (1<<1) #define PIPV4_OUTGOING (1<<2) #define PIPV4_EXTRACT_DHCP_ROUTER (1<<3) +#define PIPV4_CLIENT_NAT (1<<4) void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf); diff --git a/multi.c b/multi.c index 2808c9b..2d1b0ab 100644 --- a/multi.c +++ b/multi.c @@ -1200,6 +1200,9 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) mi->context.c2.push_ifconfig_defined = true; mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; +#ifdef ENABLE_CLIENT_NAT + mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; +#endif } else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */ { diff --git a/openvpn.8 b/openvpn.8 index 164b58e..c5eb3ca 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -1067,6 +1067,31 @@ and .B --route-gateway. .\"********************************************************* .TP +.B --client-nat snat|dnat network netmask alias +This pushable client option sets up a stateless one-to-one NAT +rule on packet addresses (not ports), and is useful in cases +where routes or ifconfig settings pushed to the client would +create an IP numbering conflict. + +.B network/netmask +(for example 192.168.0.0/255.255.0.0) +defines the local view of a resource from the client perspective, while +.B alias/netmask +(for example 10.64.0.0/255.255.0.0) +defines the remote view from the server perspective. + +Use +.B snat +(source NAT) for resources owned by the client and +.B dnat +(destination NAT) for remote resources. + +Set +.B --verb 6 +for debugging info showing the transformation of src/dest +addresses in packets. +.\"********************************************************* +.TP .B --redirect-gateway flags... (Experimental) Automatically execute routing commands to cause all outgoing IP traffic to be redirected over the VPN. @@ -2706,7 +2731,7 @@ This option is deprecated, and should be replaced with which is functionally equivalent. .\"********************************************************* .TP -.B --ifconfig-push local remote-netmask +.B --ifconfig-push local remote-netmask [alias] Push virtual IP endpoints for client tunnel, overriding the --ifconfig-pool dynamic allocation. @@ -2725,6 +2750,15 @@ are from the perspective of the client, not the server. They may be DNS names rather than IP addresses, in which case they will be resolved on the server at the time of client connection. +The optional +.B alias +parameter may be used in cases where NAT causes the client view +of its local endpoint to differ from the server view. In this case +.B local/remote-netmask +will refer to the server view while +.B alias/remote-netmask +will refer to the client view. + This option must be associated with a specific client instance, which means that it must be specified either in a client instance config file using diff --git a/openvpn.h b/openvpn.h index 0757eb1..0c4ff1a 100644 --- a/openvpn.h +++ b/openvpn.h @@ -416,6 +416,9 @@ struct context_2 bool push_ifconfig_defined; in_addr_t push_ifconfig_local; in_addr_t push_ifconfig_remote_netmask; +#ifdef ENABLE_CLIENT_NAT + in_addr_t push_ifconfig_local_alias; +#endif /* client authentication state, CAS_SUCCEEDED must be 0 */ # define CAS_SUCCEEDED 0 diff --git a/options.c b/options.c index a4b2d49..dfba941 100644 --- a/options.c +++ b/options.c @@ -198,6 +198,9 @@ static const char usage_message[] = " Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n" "--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n" " the default gateway. Useful when pushing private subnets.\n" +#ifdef ENABLE_CLIENT_NAT + "--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT rule.\n" +#endif #ifdef ENABLE_PUSH_PEER_INFO "--push-peer-info : (client only) push client info to server.\n" #endif @@ -1086,6 +1089,9 @@ options_detach (struct options *o) { gc_detach (&o->gc); o->routes = NULL; +#ifdef ENABLE_CLIENT_NAT + o->client_nat = NULL; +#endif #if P2MP_SERVER clone_push_list(o); #endif @@ -1098,6 +1104,15 @@ rol_check_alloc (struct options *options) options->routes = new_route_option_list (options->max_routes, &options->gc); } +#ifdef ENABLE_CLIENT_NAT +static void +cnol_check_alloc (struct options *options) +{ + if (!options->client_nat) + options->client_nat = new_client_nat_list (&options->gc); +} +#endif + #ifdef ENABLE_DEBUG static void show_connection_entry (const struct connection_entry *o) @@ -1288,6 +1303,11 @@ show_settings (const struct options *o) SHOW_BOOL (allow_pull_fqdn); if (o->routes) print_route_options (o->routes, D_SHOW_PARMS); + +#ifdef ENABLE_CLIENT_NAT + if (o->client_nat) + print_client_nat_list(o->client_nat, D_SHOW_PARMS); +#endif #ifdef ENABLE_MANAGEMENT SHOW_STR (management_addr); @@ -2337,6 +2357,13 @@ pre_pull_save (struct options *o) o->pre_pull->routes = clone_route_option_list(o->routes, &o->gc); o->pre_pull->routes_defined = true; } +#ifdef ENABLE_CLIENT_NAT + if (o->client_nat) + { + o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc); + o->pre_pull->client_nat_defined = true; + } +#endif } } @@ -2358,6 +2385,16 @@ pre_pull_restore (struct options *o) else o->routes = NULL; +#ifdef ENABLE_CLIENT_NAT + if (pp->client_nat_defined) + { + cnol_check_alloc (o); + copy_client_nat_option_list (o->client_nat, pp->client_nat); + } + else + o->client_nat = NULL; +#endif + o->foreign_option_index = pp->foreign_option_index; } @@ -4564,6 +4601,14 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_PERSIST_IP); options->persist_remote_ip = true; } +#ifdef ENABLE_CLIENT_NAT + else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4]) + { + VERIFY_PERMISSION (OPT_P_ROUTE); + cnol_check_alloc (options); + add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel); + } +#endif else if (streq (p[0], "route") && p[1]) { VERIFY_PERMISSION (OPT_P_ROUTE); @@ -5085,6 +5130,10 @@ add_option (struct options *options, options->push_ifconfig_defined = true; options->push_ifconfig_local = local; options->push_ifconfig_remote_netmask = remote_netmask; +#ifdef ENABLE_CLIENT_NAT + if (p[3]) + options->push_ifconfig_local_alias = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL); +#endif } else { diff --git a/options.h b/options.h index 4a56701..fd9eb7c 100644 --- a/options.h +++ b/options.h @@ -41,6 +41,7 @@ #include "proxy.h" #include "lzo.h" #include "pushlist.h" +#include "clinat.h" /* * Maximum number of parameters associated with an option, @@ -67,6 +68,11 @@ struct options_pre_pull bool routes_defined; struct route_option_list *routes; +#ifdef ENABLE_CLIENT_NAT + bool client_nat_defined; + struct client_nat_option_list *client_nat; +#endif + int foreign_option_index; }; @@ -329,6 +335,10 @@ struct options bool route_gateway_via_dhcp; bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */ +#ifdef ENABLE_CLIENT_NAT + struct client_nat_option_list *client_nat; +#endif + #ifdef ENABLE_OCC /* Enable options consistency check between peers */ bool occ; @@ -401,6 +411,9 @@ struct options bool push_ifconfig_defined; in_addr_t push_ifconfig_local; in_addr_t push_ifconfig_remote_netmask; +#ifdef ENABLE_CLIENT_NAT + in_addr_t push_ifconfig_local_alias; +#endif bool push_ifconfig_constraint_defined; in_addr_t push_ifconfig_constraint_network; in_addr_t push_ifconfig_constraint_netmask; diff --git a/proto.h b/proto.h index 55f0832..7e45231 100644 --- a/proto.h +++ b/proto.h @@ -149,6 +149,14 @@ struct openvpn_tcphdr { #define OPENVPN_TCPOPT_MAXSEG 2 #define OPENVPN_TCPOLEN_MAXSEG 4 +struct ip_tcp_udp_hdr { + struct openvpn_iphdr ip; + union { + struct openvpn_tcphdr tcp; + struct openvpn_udphdr udp; + } u; +}; + #pragma pack() /* @@ -160,19 +168,30 @@ struct openvpn_tcphdr { * is the checksum value to be updated. */ #define ADJUST_CHECKSUM(acc, cksum) { \ - (acc) += (cksum); \ - if ((acc) < 0) { \ - (acc) = -(acc); \ - (acc) = ((acc) >> 16) + ((acc) & 0xffff); \ - (acc) += (acc) >> 16; \ - (cksum) = (uint16_t) ~(acc); \ + int _acc = acc; \ + _acc += (cksum); \ + if (_acc < 0) { \ + _acc = -_acc; \ + _acc = (_acc >> 16) + (_acc & 0xffff); \ + _acc += _acc >> 16; \ + (cksum) = (uint16_t) ~_acc; \ } else { \ - (acc) = ((acc) >> 16) + ((acc) & 0xffff); \ - (acc) += (acc) >> 16; \ - (cksum) = (uint16_t) (acc); \ + _acc = (_acc >> 16) + (_acc & 0xffff); \ + _acc += _acc >> 16; \ + (cksum) = (uint16_t) _acc; \ } \ } +#define ADD_CHECKSUM_32(acc, u32) { \ + acc += (u32) & 0xffff; \ + acc += (u32) >> 16; \ +} + +#define SUB_CHECKSUM_32(acc, u32) { \ + acc -= (u32) & 0xffff; \ + acc -= (u32) >> 16; \ +} + /* * We are in a "liberal" position with respect to MSS, * i.e. we assume that MSS can be calculated from MTU diff --git a/push.c b/push.c index 0db826a..298031d 100644 --- a/push.c +++ b/push.c @@ -185,7 +185,7 @@ send_push_reply (struct context *c) struct push_entry *e = c->options.push_list.head; bool multi_push = false; static char cmd[] = "PUSH_REPLY"; - const int extra = 64; /* extra space for possible trailing ifconfig and push-continuation */ + const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */ const int safe_cap = BCAP (&buf) - extra; buf_printf (&buf, cmd); @@ -218,9 +218,16 @@ send_push_reply (struct context *c) } if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask) - buf_printf (&buf, ",ifconfig %s %s", - print_in_addr_t (c->c2.push_ifconfig_local, 0, &gc), - print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc)); + { + in_addr_t ifconfig_local = c->c2.push_ifconfig_local; +#ifdef ENABLE_CLIENT_NAT + if (c->c2.push_ifconfig_local_alias) + ifconfig_local = c->c2.push_ifconfig_local_alias; +#endif + buf_printf (&buf, ",ifconfig %s %s", + print_in_addr_t (ifconfig_local, 0, &gc), + print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc)); + } if (multi_push) buf_printf (&buf, ",push-continuation 1"); diff --git a/syshead.h b/syshead.h index 4e6ef08..1c894c9 100644 --- a/syshead.h +++ b/syshead.h @@ -692,4 +692,9 @@ socket_defined (const socket_descriptor_t sd) */ #define ENABLE_PUSH_PEER_INFO +/* + * Do we support internal client-side NAT? + */ +#define ENABLE_CLIENT_NAT + #endif diff --git a/version.m4 b/version.m4 index 72d6ea2..f89b007 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3h]) +define(PRODUCT_VERSION,[2.1.3i]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 6c34e74f1340a72ab7dce077e4d326f03989322c Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 10 Mar 2011 00:04:39 +0000 Subject: Added --enable-lzo-stub configure option to build an OpenVPN client without LZO, but that has limited interoperability with LZO-enabled servers. Modified "push-peer-info" option to push IV_LZO_STUB=1 to server when client was built with --enable-lzo-stub configure option. This tells the server that the client lacks LZO capabilities, so the server should turn off LZO compression for this client via "lzo no". Added "setenv PUSH_PEER_INFO" option having the same effect as "push-peer-info". Version 2.1.3j git-svn-id: http://svn.openvpn.net/projects/branches/BETA21@7023 e7ae566f-a301-0410-adde-c780ea21d3b5 --- configure.ac | 15 +++++++++++++-- lzo.c | 30 ++++++++++++++++++++++++++++-- lzo.h | 29 ++++++++++++++++++++--------- options.c | 6 ++++++ ssl.c | 5 +++++ syshead.h | 12 ++++++++++++ version.m4 | 2 +- 7 files changed, 85 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index 5575705..729ce40 100644 --- a/configure.ac +++ b/configure.ac @@ -69,6 +69,12 @@ AC_ARG_ENABLE(lzo, [LZO="yes"] ) +AC_ARG_ENABLE(lzo-stub, + [ --enable-lzo-stub Don't compile LZO compression support but still allow limited interoperability with LZO-enabled peers], + [LZO_STUB="$enableval"], + [LZO_STUB="no"] +) + AC_ARG_ENABLE(crypto, [ --disable-crypto Disable OpenSSL crypto support], [CRYPTO="$enableval"], @@ -657,7 +663,7 @@ dnl dnl check for LZO library dnl -if test "$LZO" = "yes"; then +if test "$LZO" = "yes" && test "$LZO_STUB" = "no"; then LZO_H="" AC_CHECKING([for LZO Library and Header files]) AC_CHECK_HEADER(lzo/lzo1x.h, @@ -687,10 +693,15 @@ if test "$LZO" = "yes"; then else AC_MSG_RESULT([LZO headers were not found]) AC_MSG_RESULT([LZO library available from http://www.oberhumer.com/opensource/lzo/]) - AC_MSG_ERROR([Or try ./configure --disable-lzo]) + AC_MSG_ERROR([Or try ./configure --disable-lzo OR ./configure --enable-lzo-stub]) fi fi +dnl enable multi-client mode +if test "$LZO_STUB" = "yes"; then + AC_DEFINE(LZO_STUB, 1, [Enable LZO stub capability]) +fi + dnl dnl check for OpenSSL-crypto library dnl diff --git a/lzo.c b/lzo.c index 6ea0d03..7343051 100644 --- a/lzo.c +++ b/lzo.c @@ -32,6 +32,8 @@ #include "memdbg.h" +#ifndef LZO_STUB + static bool lzo_adaptive_compress_test (struct lzo_adaptive_compress *ac) { @@ -79,6 +81,8 @@ lzo_adaptive_compress_data (struct lzo_adaptive_compress *ac, int n_total, int n ac->n_comp += n_comp; } +#endif /* LZO_STUB */ + void lzo_adjust_frame_parameters (struct frame *frame) { /* Leave room for our one-byte compressed/didn't-compress prefix byte. */ @@ -94,14 +98,18 @@ lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags) { CLEAR (*lzowork); - lzowork->wmem_size = LZO_WORKSPACE; lzowork->flags = flags; +#ifndef LZO_STUB + lzowork->wmem_size = LZO_WORKSPACE; if (lzo_init () != LZO_E_OK) msg (M_FATAL, "Cannot initialize LZO compression library"); lzowork->wmem = (lzo_voidp) lzo_malloc (lzowork->wmem_size); check_malloc_return (lzowork->wmem); msg (M_INFO, "LZO compression initialized"); +#else + msg (M_INFO, "LZO stub compression initialized"); +#endif lzowork->defined = true; } @@ -111,8 +119,10 @@ lzo_compress_uninit (struct lzo_compress_workspace *lzowork) if (lzowork) { ASSERT (lzowork->defined); +#ifndef LZO_STUB lzo_free (lzowork->wmem); lzowork->wmem = NULL; +#endif lzowork->defined = false; } } @@ -120,6 +130,7 @@ lzo_compress_uninit (struct lzo_compress_workspace *lzowork) static inline bool lzo_compression_enabled (struct lzo_compress_workspace *lzowork) { +#ifndef LZO_STUB if ((lzowork->flags & (LZO_SELECTED|LZO_ON)) == (LZO_SELECTED|LZO_ON)) { if (lzowork->flags & LZO_ADAPTIVE) @@ -127,6 +138,7 @@ lzo_compression_enabled (struct lzo_compress_workspace *lzowork) else return true; } +#endif return false; } @@ -139,15 +151,18 @@ lzo_compress (struct buffer *buf, struct buffer work, struct lzo_compress_workspace *lzowork, const struct frame* frame) { +#ifndef LZO_STUB lzo_uint zlen = 0; int err; bool compressed = false; +#endif ASSERT (lzowork->defined); if (buf->len <= 0) return; +#ifndef LZO_STUB /* * In order to attempt compression, length must be at least COMPRESS_THRESHOLD, * and our adaptive level must give the OK. @@ -193,6 +208,7 @@ lzo_compress (struct buffer *buf, struct buffer work, *buf = work; } else +#endif { uint8_t *header = buf_prepend (buf, 1); *header = NO_COMPRESS; @@ -204,9 +220,11 @@ lzo_decompress (struct buffer *buf, struct buffer work, struct lzo_compress_workspace *lzowork, const struct frame* frame) { +#ifndef LZO_STUB lzo_uint zlen = EXPANDED_SIZE (frame); - uint8_t c; /* flag indicating whether or not our peer compressed */ int err; +#endif + uint8_t c; /* flag indicating whether or not our peer compressed */ ASSERT (lzowork->defined); @@ -220,6 +238,7 @@ lzo_decompress (struct buffer *buf, struct buffer work, if (c == YES_COMPRESS) /* packet was compressed */ { +#ifndef LZO_STUB ASSERT (buf_safe (&work, zlen)); err = LZO_DECOMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, lzowork->wmem); @@ -238,6 +257,11 @@ lzo_decompress (struct buffer *buf, struct buffer work, lzowork->post_decompress += work.len; *buf = work; +#else + dmsg (D_COMP_ERRORS, "LZO decompression error: LZO capability not compiled"); + buf->len = 0; + return; +#endif } else if (c == NO_COMPRESS) /* packet was not compressed */ { @@ -264,10 +288,12 @@ void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct { ASSERT (lzo_compwork->defined); +#ifndef LZO_STUB status_printf (so, "pre-compress bytes," counter_format, lzo_compwork->pre_compress); status_printf (so, "post-compress bytes," counter_format, lzo_compwork->post_compress); status_printf (so, "pre-decompress bytes," counter_format, lzo_compwork->pre_decompress); status_printf (so, "post-decompress bytes," counter_format, lzo_compwork->post_decompress); +#endif } #else diff --git a/lzo.h b/lzo.h index bb15753..831f204 100644 --- a/lzo.h +++ b/lzo.h @@ -27,6 +27,7 @@ #ifdef USE_LZO +#ifndef LZO_STUB #ifdef LZO_HEADER_DIR #include "lzo/lzoutil.h" #include "lzo/lzo1x.h" @@ -34,6 +35,7 @@ #include "lzoutil.h" #include "lzo1x.h" #endif +#endif #include "buffer.h" #include "mtu.h" @@ -45,6 +47,18 @@ #define LZO_ON (1<<1) #define LZO_ADAPTIVE (1<<2) +/* + * Length of prepended prefix on LZO packets + */ +#define LZO_PREFIX_LEN 1 + +/* + * LZO 2.0 worst case size expansion + */ +#define LZO_EXTRA_BUFFER(len) ((len)/8 + 128 + 3) + +#ifndef LZO_STUB + /* * Use LZO compress routine lzo1x_1_15_compress which is described * as faster but needs a bit more memory than the standard routine. @@ -58,18 +72,11 @@ #define LZO_WORKSPACE LZO1X_1_15_MEM_COMPRESS #define LZO_DECOMPRESS lzo1x_decompress_safe -#define LZO_EXTRA_BUFFER(len) ((len)/8 + 128 + 3) /* LZO 2.0 worst case size expansion. */ - /* * Don't try to compress any packet smaller than this. */ #define COMPRESS_THRESHOLD 100 -/* - * Length of prepended prefix on LZO packets - */ -#define LZO_PREFIX_LEN 1 - /* * Adaptive compress parameters */ @@ -88,23 +95,27 @@ struct lzo_adaptive_compress { int n_comp; }; +#endif /* LZO_STUB */ + /* * Compress and Uncompress routines. */ struct lzo_compress_workspace { + bool defined; + unsigned int flags; +#ifndef LZO_STUB lzo_voidp wmem; int wmem_size; struct lzo_adaptive_compress ac; - unsigned int flags; - bool defined; /* statistics */ counter_type pre_decompress; counter_type post_decompress; counter_type pre_compress; counter_type post_compress; +#endif }; void lzo_adjust_frame_parameters(struct frame *frame); diff --git a/options.c b/options.c index dfba941..e8e0d7a 100644 --- a/options.c +++ b/options.c @@ -4754,6 +4754,12 @@ add_option (struct options *options, msg (msglevel, "this is a generic configuration and cannot directly be used"); goto err; } +#ifdef ENABLE_PUSH_PEER_INFO + else if (streq (p[1], "PUSH_PEER_INFO")) + { + options->push_peer_info = true; + } +#endif #if P2MP else if (streq (p[1], "SERVER_POLL_TIMEOUT") && p[2]) { diff --git a/ssl.c b/ssl.c index 16e4c09..dbc65eb 100644 --- a/ssl.c +++ b/ssl.c @@ -3809,6 +3809,11 @@ push_peer_info(struct buffer *buf, struct tls_session *session) buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (macaddr, 6, 0, 1, ":", &gc)); } + /* push LZO status */ +#ifdef LZO_STUB + buf_printf (&out, "IV_LZO_STUB=1\n"); +#endif + /* push env vars that begin with UV_ */ for (e=es->list; e != NULL; e=e->next) { diff --git a/syshead.h b/syshead.h index 1c894c9..0da1fc2 100644 --- a/syshead.h +++ b/syshead.h @@ -697,4 +697,16 @@ socket_defined (const socket_descriptor_t sd) */ #define ENABLE_CLIENT_NAT +/* + * Support LZO as a stub in client? (LZO lib not included, but we + * we still support LZO protocol changes that allow us to + * communicate with an LZO-enabled server) + */ +#ifdef LZO_STUB +#undef USE_LZO +#undef LZO_VERSION_NUM +#define USE_LZO 1 +#define LZO_VERSION_NUM "STUB" +#endif + #endif diff --git a/version.m4 b/version.m4 index f89b007..e173442 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3i]) +define(PRODUCT_VERSION,[2.1.3j]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 1c5ff7722dbd3e32aa3e5b7d5cb77773f083472d Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sun, 13 Mar 2011 06:59:25 +0000 Subject: Added optional journal directory argument to "port-share" directive, for reporting client IP origins of proxied connections. git-svn-id: http://svn.openvpn.net/projects/branches/BETA21@7031 e7ae566f-a301-0410-adde-c780ea21d3b5 --- error.c | 29 ++++++++++-------- event.c | 4 +-- init.c | 4 ++- openvpn.8 | 12 +++++++- options.c | 6 ++-- options.h | 1 + ps.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- ps.h | 4 ++- 8 files changed, 131 insertions(+), 33 deletions(-) diff --git a/error.c b/error.c index 873718c..9cf4547 100644 --- a/error.c +++ b/error.c @@ -353,7 +353,7 @@ void x_msg (const unsigned int flags, const char *format, ...) } if (flags & M_FATAL) - msg (M_INFO, "Exiting"); + msg (M_INFO, "Exiting due to fatal error"); mutex_unlock_static (L_MSG); @@ -690,35 +690,38 @@ msg_thread_uninit (void) void openvpn_exit (const int status) { - void tun_abort(); + if (!forked) + { + void tun_abort(); #ifdef ENABLE_PLUGIN - void plugin_abort (void); + void plugin_abort (void); #endif - tun_abort(); + tun_abort(); #ifdef WIN32 - uninit_win32 (); + uninit_win32 (); #endif - close_syslog (); + close_syslog (); #ifdef ENABLE_PLUGIN - plugin_abort (); + plugin_abort (); #endif #if PORT_SHARE - if (port_share) - port_share_abort (port_share); + if (port_share) + port_share_abort (port_share); #endif #ifdef ABORT_ON_ERROR - if (status == OPENVPN_EXIT_STATUS_ERROR) - abort (); + if (status == OPENVPN_EXIT_STATUS_ERROR) + abort (); #endif - if (status == OPENVPN_EXIT_STATUS_GOOD) - perf_output_results (); + if (status == OPENVPN_EXIT_STATUS_GOOD) + perf_output_results (); + } exit (status); } diff --git a/event.c b/event.c index 6a9161b..51b17b3 100644 --- a/event.c +++ b/event.c @@ -522,10 +522,10 @@ ep_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) if (errno == ENOENT) { if (epoll_ctl (eps->epfd, EPOLL_CTL_ADD, event, &ev) < 0) - msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed"); + msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed, sd=%d", (int)event); } else - msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed"); + msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed, sd=%d", (int)event); } } diff --git a/init.c b/init.c index 70357e1..4214233 100644 --- a/init.c +++ b/init.c @@ -520,7 +520,9 @@ init_port_share (struct context *c) if (!port_share && (c->options.port_share_host && c->options.port_share_port)) { port_share = port_share_open (c->options.port_share_host, - c->options.port_share_port); + c->options.port_share_port, + MAX_RW_SIZE_LINK (&c->c2.frame), + c->options.port_share_journal_dir); if (port_share == NULL) msg (M_FATAL, "Fatal error: Port sharing failed"); } diff --git a/openvpn.8 b/openvpn.8 index c5eb3ca..037ba7e 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -3240,7 +3240,7 @@ disable the remapping feature. Don't use this option unless you know what you are doing! .\"********************************************************* .TP -.B --port-share host port +.B --port-share host port [dir] When run in TCP server mode, share the OpenVPN port with another application, such as an HTTPS server. If OpenVPN senses a connection to its port which is using a non-OpenVPN @@ -3250,6 +3250,16 @@ Currently only designed to work with HTTP/HTTPS, though it would be theoretically possible to extend to other protocols such as ssh. +.B dir +specifies an optional directory where a temporary file with name N +containing content C will be dynamically generated for each proxy +connection, where N is the source IP:port of the client connection +and C is the source IP:port of the connection to the proxy +receiver. This directory can be used as a dictionary by +the proxy receiver to determine the origin of the connection. +Each generated file will be automatically deleted when the proxied +connection is torn down. + Not implemented on Windows. .\"********************************************************* .SS Client Mode diff --git a/options.c b/options.c index e8e0d7a..8ace13f 100644 --- a/options.c +++ b/options.c @@ -427,8 +427,9 @@ static const char usage_message[] = "--max-clients n : Allow a maximum of n simultaneously connected clients.\n" "--max-routes-per-client n : Allow a maximum of n internal routes per client.\n" #if PORT_SHARE - "--port-share host port : When run in TCP mode, proxy incoming HTTPS sessions\n" - " to a web server at host:port.\n" + "--port-share host port [dir] : When run in TCP mode, proxy incoming HTTPS\n" + " sessions to a web server at host:port. dir specifies an\n" + " optional directory to write origin IP:port data.\n" #endif #endif "\n" @@ -5101,6 +5102,7 @@ add_option (struct options *options, options->port_share_host = p[1]; options->port_share_port = port; + options->port_share_journal_dir = p[3]; } #endif else if (streq (p[0], "client-to-client")) diff --git a/options.h b/options.h index fd9eb7c..74ba9d4 100644 --- a/options.h +++ b/options.h @@ -430,6 +430,7 @@ struct options #if PORT_SHARE char *port_share_host; int port_share_port; + const char *port_share_journal_dir; #endif #endif diff --git a/ps.c b/ps.c index c77e769..26cf4cb 100644 --- a/ps.c +++ b/ps.c @@ -69,6 +69,7 @@ struct proxy_connection { bool buffer_initial; int rwflags; int sd; + char *jfn; }; #if 0 @@ -226,7 +227,7 @@ port_share_sendmsg (const socket_descriptor_t sd, status = sendmsg (sd, &mesg, MSG_NOSIGNAL); if (status == -1) - msg (M_WARN, "PORT SHARE: sendmsg failed (unable to communicate with background process)"); + msg (M_WARN|M_ERRNO_SOCK, "PORT SHARE: sendmsg failed (unable to communicate with background process)"); close_socket_if_defined (sd_null[0]); close_socket_if_defined (sd_null[1]); @@ -273,6 +274,12 @@ proxy_entry_mark_for_close (struct proxy_connection *pc, struct event_set *es) pc->buffer_initial = false; pc->rwflags = 0; pc->defined = false; + if (pc->jfn) + { + unlink (pc->jfn); + free (pc->jfn); + pc->jfn = NULL; + } if (cp && cp->defined && cp->counterpart == pc) proxy_entry_mark_for_close (cp, es); } @@ -308,6 +315,48 @@ proxy_list_housekeeping (struct proxy_connection **list) } } +/* + * Record IP/port of client in filesystem, so that server receiving + * the proxy can determine true client origin. + */ +static void +journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_connection *cp) +{ + struct gc_arena gc = gc_new (); + struct openvpn_sockaddr from, to; + socklen_t slen, dlen; + int fnlen; + char *jfn; + int fd; + + slen = sizeof(from.sa); + dlen = sizeof(to.sa); + if (!getpeername (pc->sd, (struct sockaddr *) &from.sa, &slen) + && !getsockname (cp->sd, (struct sockaddr *) &to.sa, &dlen)) + { + const char *f = print_sockaddr_ex (&from, ":", PS_SHOW_PORT, &gc); + const char *t = print_sockaddr_ex (&to, ":", PS_SHOW_PORT, &gc); + fnlen = strlen(journal_dir) + strlen(t) + 2; + jfn = (char *) malloc(fnlen); + check_malloc_return (jfn); + openvpn_snprintf (jfn, fnlen, "%s/%s", journal_dir, t); + dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: client origin %s -> %s", jfn, f); + fd = open (jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); + if (fd != -1) + { + write(fd, f, strlen(f)); + close (fd); + cp->jfn = jfn; + } + else + { + msg (M_WARN|M_ERRNO, "PORT SHARE: unable to write journal file in %s", jfn); + free (jfn); + } + } + gc_free (&gc); +} + /* * Cleanup function, on proxy process exit. */ @@ -361,7 +410,8 @@ proxy_entry_new (struct proxy_connection **list, const in_addr_t server_addr, const int server_port, const socket_descriptor_t sd_client, - struct buffer *initial_data) + struct buffer *initial_data, + const char *journal_dir) { struct openvpn_sockaddr osaddr; socket_descriptor_t sd_server; @@ -371,7 +421,11 @@ proxy_entry_new (struct proxy_connection **list, /* connect to port share server */ sock_addr_set (&osaddr, server_addr, server_port); - sd_server = create_socket_tcp (); + if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + msg (M_WARN|M_ERRNO_SOCK, "PORT SHARE PROXY: cannot create socket"); + return false; + } status = openvpn_connect (sd_server, &osaddr, 5, NULL); if (status) { @@ -408,6 +462,10 @@ proxy_entry_new (struct proxy_connection **list, /* add to list */ *list = pc; + + /* add journal entry */ + if (journal_dir) + journal_add (journal_dir, pc, cp); dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: NEW CONNECTION [c=%d s=%d]", (int)sd_client, (int)sd_server); @@ -429,9 +487,14 @@ control_message_from_parent (const socket_descriptor_t sd_control, struct proxy_connection **list, struct event_set *es, const in_addr_t server_addr, - const int server_port) + const int server_port, + const int max_initial_buf, + const char *journal_dir) { - struct buffer buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE); + /* this buffer needs to be large enough to handle the largest buffer + that might be returned by the link_socket_read call in read_incoming_link. */ + struct buffer buf = alloc_buf (max_initial_buf); + struct msghdr mesg; struct cmsghdr* h; struct iovec iov[2]; @@ -467,7 +530,7 @@ control_message_from_parent (const socket_descriptor_t sd_control, || h->cmsg_level != SOL_SOCKET || h->cmsg_type != SCM_RIGHTS ) { - ret = false; + msg (M_WARN, "PORT SHARE PROXY: received unknown message"); } else { @@ -482,7 +545,8 @@ control_message_from_parent (const socket_descriptor_t sd_control, server_addr, server_port, received_fd, - &buf)) + &buf, + journal_dir)) { CLEAR (buf); /* we gave the buffer to proxy_entry_new */ } @@ -517,6 +581,7 @@ proxy_connection_io_recv (struct proxy_connection *pc) { if (!status) return IOSTAT_READ_ERROR; + dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: read[%d] %d", (int)pc->sd, status); pc->buf.len = status; } return IOSTAT_GOOD; @@ -544,7 +609,7 @@ proxy_connection_io_send (struct proxy_connection *pc, int *bytes_sent) } else { - /*dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status);*/ + dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status); pc->buf.len = 0; pc->buf.offset = 0; } @@ -627,6 +692,8 @@ proxy_connection_io_dispatch (struct proxy_connection *pc, int rwflags_pc = pc->rwflags; int rwflags_cp = cp->rwflags; + ASSERT(pc->defined && cp->defined && cp->counterpart == pc); + if (rwflags & EVENT_READ) { const int status = proxy_connection_io_xfer (pc, max_transfer_per_iteration); @@ -653,7 +720,11 @@ proxy_connection_io_dispatch (struct proxy_connection *pc, * This is the main function for the port share proxy background process. */ static void -port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descriptor_t sd_control) +port_share_proxy (const in_addr_t hostaddr, + const int port, + const socket_descriptor_t sd_control, + const int max_initial_buf, + const char *journal_dir) { if (send_control (sd_control, RESPONSE_INIT_SUCCEEDED) >= 0) { @@ -687,7 +758,7 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip const struct event_set_return *e = &esr[i]; if (e->arg == sd_control_marker) { - if (!control_message_from_parent (sd_control, &list, es, hostaddr, port)) + if (!control_message_from_parent (sd_control, &list, es, hostaddr, port, max_initial_buf, journal_dir)) goto done; } else @@ -713,7 +784,7 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip proxy_list_close (&list); event_free (es); } - msg (D_PS_PROXY, "PORT SHARE PROXY: proxy exiting"); + msg (M_INFO, "PORT SHARE PROXY: proxy exiting"); } /* @@ -721,7 +792,10 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip * share proxy. */ struct port_share * -port_share_open (const char *host, const int port) +port_share_open (const char *host, + const int port, + const int max_initial_buf, + const char *journal_dir) { pid_t pid; socket_descriptor_t fd[2]; @@ -766,6 +840,10 @@ port_share_open (const char *host, const int port) /* don't let future subprocesses inherit child socket */ set_cloexec (fd[0]); + /* note that this will cause possible EAGAIN when writing to + control socket if proxy process is backlogged */ + set_nonblock (fd[0]); + /* wait for background child process to initialize */ status = recv_control (fd[0]); if (status == RESPONSE_INIT_SUCCEEDED) @@ -796,7 +874,7 @@ port_share_open (const char *host, const int port) prng_init (NULL, 0); /* execute the event loop */ - port_share_proxy (hostaddr, port, fd[1]); + port_share_proxy (hostaddr, port, fd[1], max_initial_buf, journal_dir); openvpn_close_socket (fd[1]); diff --git a/ps.h b/ps.h index d488a72..4280635 100644 --- a/ps.h +++ b/ps.h @@ -44,7 +44,9 @@ struct port_share { extern struct port_share *port_share; struct port_share *port_share_open (const char *host, - const int port); + const int port, + const int max_initial_buf, + const char *journal_dir); void port_share_close (struct port_share *ps); void port_share_abort (struct port_share *ps); -- cgit v1.2.3 From 9df9e13f7c20e0c046b71de859e08a07edf0eb4f Mon Sep 17 00:00:00 2001 From: James Yonan Date: Tue, 15 Mar 2011 05:06:23 +0000 Subject: Reduce log verbosity at level 3, with a focus on removing excessive log verbosity generated by port-share activity. Version 2.1.3k git-svn-id: http://svn.openvpn.net/projects/branches/BETA21@7033 e7ae566f-a301-0410-adde-c780ea21d3b5 --- errlevel.h | 16 +++++++++------- init.c | 2 +- lzo.c | 4 ++-- multi.c | 2 +- socket.c | 34 +++++++++++++++++++--------------- version.m4 | 2 +- 6 files changed, 33 insertions(+), 27 deletions(-) diff --git a/errlevel.h b/errlevel.h index a47edac..13a7114 100644 --- a/errlevel.h +++ b/errlevel.h @@ -71,9 +71,7 @@ #define D_ALIGN_ERRORS LOGLEV(1, 14, M_NONFATAL) /* show bad struct alignments */ #define D_HANDSHAKE LOGLEV(2, 20, 0) /* show data & control channel handshakes */ -#define D_MTU_INFO LOGLEV(2, 21, 0) /* show terse MTU info */ #define D_CLOSE LOGLEV(2, 22, 0) /* show socket and TUN/TAP close */ -#define D_SHOW_OCC_HASH LOGLEV(2, 23, 0) /* show MD5 hash of option compatibility string */ #define D_PROXY LOGLEV(2, 24, 0) /* show http proxy control packets */ #define D_ARGV LOGLEV(2, 25, 0) /* show struct argv errors */ @@ -104,14 +102,18 @@ #define D_PACKET_TRUNC_ERR LOGLEV(4, 55, 0) /* PACKET_TRUNCATION_CHECK */ #define D_PF_DROPPED LOGLEV(4, 56, 0) /* packet filter dropped a packet */ #define D_MULTI_DROPPED LOGLEV(4, 57, 0) /* show point-to-multipoint packet drops */ -#define D_X509_ATTR LOGLEV(4, 58, 0) /* show x509-track attributes on connection */ +#define D_MULTI_MEDIUM LOGLEV(4, 58, 0) /* show medium frequency multi messages */ +#define D_X509_ATTR LOGLEV(4, 59, 0) /* show x509-track attributes on connection */ +#define D_INIT_MEDIUM LOGLEV(4, 60, 0) /* show medium frequency init messages */ +#define D_MTU_INFO LOGLEV(4, 61, 0) /* show terse MTU info */ +#define D_SHOW_OCC_HASH LOGLEV(4, 62, 0) /* show MD5 hash of option compatibility string */ #define D_LOG_RW LOGLEV(5, 0, 0) /* Print 'R' or 'W' to stdout for read/write */ -#define D_LINK_RW LOGLEV(6, 60, M_DEBUG) /* show TCP/UDP reads/writes (terse) */ -#define D_TUN_RW LOGLEV(6, 60, M_DEBUG) /* show TUN/TAP reads/writes */ -#define D_TAP_WIN32_DEBUG LOGLEV(6, 60, M_DEBUG) /* show TAP-Win32 driver debug info */ -#define D_CLIENT_NAT LOGLEV(6, 60, M_DEBUG) /* show client NAT debug info */ +#define D_LINK_RW LOGLEV(6, 69, M_DEBUG) /* show TCP/UDP reads/writes (terse) */ +#define D_TUN_RW LOGLEV(6, 69, M_DEBUG) /* show TUN/TAP reads/writes */ +#define D_TAP_WIN32_DEBUG LOGLEV(6, 69, M_DEBUG) /* show TAP-Win32 driver debug info */ +#define D_CLIENT_NAT LOGLEV(6, 69, M_DEBUG) /* show client NAT debug info */ #define D_SHOW_KEYS LOGLEV(7, 70, M_DEBUG) /* show data channel encryption keys */ #define D_SHOW_KEY_SOURCE LOGLEV(7, 70, M_DEBUG) /* show data channel key source entropy */ diff --git a/init.c b/init.c index 4214233..d0a1baa 100644 --- a/init.c +++ b/init.c @@ -1981,7 +1981,7 @@ do_init_crypto_tls_c1 (struct context *c) } else { - msg (M_INFO, "Re-using SSL/TLS context"); + msg (D_INIT_MEDIUM, "Re-using SSL/TLS context"); } } diff --git a/lzo.c b/lzo.c index 7343051..3d6aa5a 100644 --- a/lzo.c +++ b/lzo.c @@ -106,9 +106,9 @@ lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags) msg (M_FATAL, "Cannot initialize LZO compression library"); lzowork->wmem = (lzo_voidp) lzo_malloc (lzowork->wmem_size); check_malloc_return (lzowork->wmem); - msg (M_INFO, "LZO compression initialized"); + msg (D_INIT_MEDIUM, "LZO compression initialized"); #else - msg (M_INFO, "LZO stub compression initialized"); + msg (D_INIT_MEDIUM, "LZO stub compression initialized"); #endif lzowork->defined = true; } diff --git a/multi.c b/multi.c index 2d1b0ab..df96ba5 100644 --- a/multi.c +++ b/multi.c @@ -629,7 +629,7 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real) perf_push (PERF_MULTI_CREATE_INSTANCE); - msg (D_MULTI_LOW, "MULTI: multi_create_instance called"); + msg (D_MULTI_MEDIUM, "MULTI: multi_create_instance called"); ALLOC_OBJ_CLEAR (mi, struct multi_instance); diff --git a/socket.c b/socket.c index 8153209..8e58250 100644 --- a/socket.c +++ b/socket.c @@ -1551,21 +1551,25 @@ link_socket_init_phase2 (struct link_socket *sock, #endif /* print local address */ - if (sock->inetd) - msg (M_INFO, "%s link local: [inetd]", proto2ascii (sock->info.proto, true)); - else - msg (M_INFO, "%s link local%s: %s", + { + const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO; + + if (sock->inetd) + msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, true)); + else + msg (msglevel, "%s link local%s: %s", + proto2ascii (sock->info.proto, true), + (sock->bind_local ? " (bound)" : ""), + print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc)); + + /* print active remote address */ + msg (msglevel, "%s link remote: %s", proto2ascii (sock->info.proto, true), - (sock->bind_local ? " (bound)" : ""), - print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc)); - - /* print active remote address */ - msg (M_INFO, "%s link remote: %s", - proto2ascii (sock->info.proto, true), - print_link_socket_actual_ex (&sock->info.lsa->actual, - ":", - PS_SHOW_PORT_IF_DEFINED, - &gc)); + print_link_socket_actual_ex (&sock->info.lsa->actual, + ":", + PS_SHOW_PORT_IF_DEFINED, + &gc)); + } done: if (sig_save && signal_received) @@ -1594,7 +1598,7 @@ link_socket_close (struct link_socket *sock) #endif if (!gremlin) { - msg (D_CLOSE, "TCP/UDP: Closing socket"); + msg (D_LOW, "TCP/UDP: Closing socket"); if (openvpn_close_socket (sock->sd)) msg (M_WARN | M_ERRNO_SOCK, "TCP/UDP: Close Socket failed"); } diff --git a/version.m4 b/version.m4 index e173442..e3825f2 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3j]) +define(PRODUCT_VERSION,[2.1.3k]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From a74b741b6114d29ad68766139dbcd9dfcf715c4a Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 17 Mar 2011 20:04:56 +0000 Subject: env_filter_match now includes the serial number of all certs in chain (as tls_serial_n vars), rather than only tls_serial_0. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7055 e7ae566f-a301-0410-adde-c780ea21d3b5 --- manage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manage.c b/manage.c index e8f67cd..0939105 100644 --- a/manage.c +++ b/manage.c @@ -2259,7 +2259,7 @@ env_filter_match (const char *env_str, const int env_filter_level) "username=", "password=", "X509_0_CN=", - "tls_serial_0=", + "tls_serial_", "untrusted_ip=", "ifconfig_local=", "ifconfig_netmask=", -- cgit v1.2.3 From ff65da3a230b658b2c1d52dc1a48612e80a2eb42 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Fri, 18 Mar 2011 04:51:59 +0000 Subject: Fixed issue where a client might receive multiple push replies from a server if it sent multiple push requests due to the server being slow to respond. This could cause the client to process pushed options twice, leading to duplicate pushed routes, among other issues. The fix, implemented server-side, is to reply only once to a push request even if multiple requests are received. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7060 e7ae566f-a301-0410-adde-c780ea21d3b5 --- openvpn.h | 1 + push.c | 14 ++++++++++++-- push.h | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/openvpn.h b/openvpn.h index 0c4ff1a..47c9734 100644 --- a/openvpn.h +++ b/openvpn.h @@ -414,6 +414,7 @@ struct context_2 /* --ifconfig endpoints to be pushed to client */ bool push_reply_deferred; bool push_ifconfig_defined; + bool sent_push_reply; in_addr_t push_ifconfig_local; in_addr_t push_ifconfig_remote_netmask; #ifdef ENABLE_CLIENT_NAT diff --git a/push.c b/push.c index 298031d..f7b7d17 100644 --- a/push.c +++ b/push.c @@ -331,8 +331,18 @@ process_incoming_push_msg (struct context *c, } else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) { - if (send_push_reply (c)) - ret = PUSH_MSG_REQUEST; + if (c->c2.sent_push_reply) + { + ret = PUSH_MSG_ALREADY_REPLIED; + } + else + { + if (send_push_reply (c)) + { + ret = PUSH_MSG_REQUEST; + c->c2.sent_push_reply = true; + } + } } else { diff --git a/push.h b/push.h index 089cf45..b5d1fbf 100644 --- a/push.h +++ b/push.h @@ -35,6 +35,7 @@ #define PUSH_MSG_REQUEST_DEFERRED 3 #define PUSH_MSG_AUTH_FAILURE 4 #define PUSH_MSG_CONTINUATION 5 +#define PUSH_MSG_ALREADY_REPLIED 6 void incoming_push_message (struct context *c, const struct buffer *buffer); -- cgit v1.2.3 From 3530e5fba87dd060d8009bd57d1ba8976d0e8668 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sun, 20 Mar 2011 03:57:28 +0000 Subject: Fixed bug introduced in r7031 that might cause this error message: PORT SHARE: sendmsg failed (unable to communicate with background process) git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7062 e7ae566f-a301-0410-adde-c780ea21d3b5 --- ps.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ps.c b/ps.c index 26cf4cb..5b1792a 100644 --- a/ps.c +++ b/ps.c @@ -227,7 +227,9 @@ port_share_sendmsg (const socket_descriptor_t sd, status = sendmsg (sd, &mesg, MSG_NOSIGNAL); if (status == -1) - msg (M_WARN|M_ERRNO_SOCK, "PORT SHARE: sendmsg failed (unable to communicate with background process)"); + msg (M_WARN|M_ERRNO_SOCK, "PORT SHARE: sendmsg failed -- unable to communicate with background process (%d,%d,%d,%d)", + sd, sd_send, sd_null[0], sd_null[1] + ); close_socket_if_defined (sd_null[0]); close_socket_if_defined (sd_null[1]); @@ -803,6 +805,8 @@ port_share_open (const char *host, struct port_share *ps; ALLOC_OBJ_CLEAR (ps, struct port_share); + ps->foreground_fd = -1; + ps->background_pid = -1; /* * Get host's IP address @@ -840,17 +844,21 @@ port_share_open (const char *host, /* don't let future subprocesses inherit child socket */ set_cloexec (fd[0]); - /* note that this will cause possible EAGAIN when writing to - control socket if proxy process is backlogged */ - set_nonblock (fd[0]); - /* wait for background child process to initialize */ status = recv_control (fd[0]); if (status == RESPONSE_INIT_SUCCEEDED) { + /* note that this will cause possible EAGAIN when writing to + control socket if proxy process is backlogged */ + set_nonblock (fd[0]); + ps->foreground_fd = fd[0]; return ps; } + else + { + msg (M_SOCKERR, "PORT SHARE: unexpected init recv_control status=%d", status); + } } else { @@ -959,7 +967,9 @@ void port_share_redirect (struct port_share *ps, const struct buffer *head, socket_descriptor_t sd) { if (ps) - port_share_sendmsg (ps->foreground_fd, COMMAND_REDIRECT, head, sd); + { + port_share_sendmsg (ps->foreground_fd, COMMAND_REDIRECT, head, sd); + } } #endif -- cgit v1.2.3 From e1b99e6b6630a81ffd3287bc11533707332d2dda Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sun, 20 Mar 2011 04:12:26 +0000 Subject: Extended "client-kill" management interface command (server-side) to accept an optional message string. The message string format is: RESTART|HALT, RESTART will tell the client to restart (i.e. SIGUSR1). HALT will tell the client to exit (i.e. SIGTERM). On the client, human-readable-message will be communicated via management interface: >NOTIFY,,," Version 2.1.3m git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7063 e7ae566f-a301-0410-adde-c780ea21d3b5 --- forward.c | 11 +++++++++-- manage.c | 17 ++++++++++++----- manage.h | 4 +++- multi.c | 5 +++-- push.c | 29 +++++++++++++++++++++++------ push.h | 4 ++-- version.m4 | 2 +- 7 files changed, 53 insertions(+), 19 deletions(-) diff --git a/forward.c b/forward.c index ce0a7c4..65b8f0c 100644 --- a/forward.c +++ b/forward.c @@ -155,7 +155,9 @@ check_incoming_control_channel_dowork (struct context *c) else if (buf_string_match_head_str (&buf, "PUSH_")) incoming_push_message (c, &buf); else if (buf_string_match_head_str (&buf, "RESTART")) - server_pushed_restart (c, &buf); + server_pushed_signal (c, &buf, true, 7); + else if (buf_string_match_head_str (&buf, "HALT")) + server_pushed_signal (c, &buf, false, 4); else msg (D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR (&buf)); } @@ -237,7 +239,12 @@ send_control_channel_string (struct context *c, const char *str, int msglevel) /* buffered cleartext write onto TLS control channel */ stat = tls_send_payload (c->c2.tls_multi, (uint8_t*) str, strlen (str) + 1); - /* reschedule tls_multi_process */ + /* + * Reschedule tls_multi_process. + * NOTE: in multi-client mode, usually the below two statements are + * insufficient to reschedule the client instance object unless + * multi_schedule_context_wakeup(m, mi) is also called. + */ interval_action (&c->c2.tmp_int); context_immediate_reschedule (c); /* ZERO-TIMEOUT */ diff --git a/manage.c b/manage.c index 0939105..67f87d6 100644 --- a/manage.c +++ b/manage.c @@ -96,7 +96,7 @@ man_help () msg (M_CLIENT, "client-auth-nt CID KID : Authenticate client-id/key-id CID/KID"); msg (M_CLIENT, "client-deny CID KID R [CR] : Deny auth client-id/key-id CID/KID with log reason"); msg (M_CLIENT, " text R and optional client reason text CR"); - msg (M_CLIENT, "client-kill CID : Kill client instance CID"); + msg (M_CLIENT, "client-kill CID [M] : Kill client instance CID with message M (def=RESTART)"); msg (M_CLIENT, "env-filter [level] : Set env-var filter level"); #ifdef MANAGEMENT_PF msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)"); @@ -947,14 +947,14 @@ man_client_deny (struct management *man, const char *cid_str, const char *kid_st } static void -man_client_kill (struct management *man, const char *cid_str) +man_client_kill (struct management *man, const char *cid_str, const char *kill_msg) { unsigned long cid = 0; if (parse_cid (cid_str, &cid)) { if (man->persist.callback.kill_by_cid) { - const bool status = (*man->persist.callback.kill_by_cid) (man->persist.callback.arg, cid); + const bool status = (*man->persist.callback.kill_by_cid) (man->persist.callback.arg, cid, kill_msg); if (status) { msg (M_CLIENT, "SUCCESS: client-kill command succeeded"); @@ -1265,8 +1265,8 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch #ifdef MANAGEMENT_DEF_AUTH else if (streq (p[0], "client-kill")) { - if (man_need (man, p, 1, 0)) - man_client_kill (man, p[1]); + if (man_need (man, p, 1, MN_AT_LEAST)) + man_client_kill (man, p[1], p[2]); } else if (streq (p[0], "client-deny")) { @@ -2190,6 +2190,7 @@ management_open (struct management *man, void management_close (struct management *man) { + man_output_list_push_finalize (man); /* flush output queue */ man_connection_close (man); man_settings_close (&man->settings); man_persist_close (&man->persist); @@ -2332,6 +2333,12 @@ management_up_down(struct management *man, const char *updown, const struct env_ } } +void +management_notify(struct management *man, const char *severity, const char *type, const char *text) +{ + msg (M_CLIENT, ">NOTIFY:%s,%s,%s", severity, type, text); +} + #ifdef MANAGEMENT_DEF_AUTH static bool diff --git a/manage.h b/manage.h index 18b1564..5e0696b 100644 --- a/manage.h +++ b/manage.h @@ -156,7 +156,7 @@ struct management_callback void (*delete_event) (void *arg, event_t event); int (*n_clients) (void *arg); #ifdef MANAGEMENT_DEF_AUTH - bool (*kill_by_cid) (void *arg, const unsigned long cid); + bool (*kill_by_cid) (void *arg, const unsigned long cid, const char *kill_msg); bool (*client_auth) (void *arg, const unsigned long cid, const unsigned int mda_key_id, @@ -375,6 +375,8 @@ void management_event_loop_n_seconds (struct management *man, int sec); void management_up_down(struct management *man, const char *updown, const struct env_set *es); +void management_notify(struct management *man, const char *severity, const char *type, const char *text); + #ifdef MANAGEMENT_DEF_AUTH void management_notify_client_needing_auth (struct management *management, const unsigned int auth_id, diff --git a/multi.c b/multi.c index df96ba5..4ab1e72 100644 --- a/multi.c +++ b/multi.c @@ -2544,13 +2544,14 @@ lookup_by_cid (struct multi_context *m, const unsigned long cid) } static bool -management_kill_by_cid (void *arg, const unsigned long cid) +management_kill_by_cid (void *arg, const unsigned long cid, const char *kill_msg) { struct multi_context *m = (struct multi_context *) arg; struct multi_instance *mi = lookup_by_cid (m, cid); if (mi) { - send_restart (&mi->context); /* was: multi_signal_instance (m, mi, SIGTERM); */ + send_restart (&mi->context, kill_msg); /* was: multi_signal_instance (m, mi, SIGTERM); */ + multi_schedule_context_wakeup(m, mi); return true; } else diff --git a/push.c b/push.c index f7b7d17..2e8aa55 100644 --- a/push.c +++ b/push.c @@ -87,13 +87,30 @@ receive_auth_failed (struct context *c, const struct buffer *buffer) * Act on received restart message from server */ void -server_pushed_restart (struct context *c, const struct buffer *buffer) +server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv) { if (c->options.pull) { - msg (D_STREAM_ERRORS, "Connection reset command was pushed by server"); - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ - c->sig->signal_text = "server-pushed-connection-reset"; + struct buffer buf = *buffer; + const char *m = ""; + if (buf_advance (&buf, adv) && buf_read_u8 (&buf) == ',' && BLEN (&buf)) + m = BSTR (&buf); + if (restart) + { + msg (D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m); + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ + c->sig->signal_text = "server-pushed-connection-reset"; + } + else + { + msg (D_STREAM_ERRORS, "Halt command was pushed by server ('%s')", m); + c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- server-pushed halt */ + c->sig->signal_text = "server-pushed-halt"; + } +#ifdef ENABLE_MANAGEMENT + if (management) + management_notify (management, "info", c->sig->signal_text, m); +#endif } } @@ -130,10 +147,10 @@ send_auth_failed (struct context *c, const char *client_reason) * Send restart message from server to client. */ void -send_restart (struct context *c) +send_restart (struct context *c, const char *kill_msg) { schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM); - send_control_channel_string (c, "RESTART", D_PUSH); + send_control_channel_string (c, kill_msg ? kill_msg : "RESTART", D_PUSH); } #endif diff --git a/push.h b/push.h index b5d1fbf..8c3f157 100644 --- a/push.h +++ b/push.h @@ -50,7 +50,7 @@ bool send_push_request (struct context *c); void receive_auth_failed (struct context *c, const struct buffer *buffer); -void server_pushed_restart (struct context *c, const struct buffer *buffer); +void server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv); #if P2MP_SERVER @@ -67,7 +67,7 @@ void remove_iroutes_from_push_route_list (struct options *o); void send_auth_failed (struct context *c, const char *client_reason); -void send_restart (struct context *c); +void send_restart (struct context *c, const char *kill_msg); #endif #endif diff --git a/version.m4 b/version.m4 index e3825f2..f3e7a8d 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3k]) +define(PRODUCT_VERSION,[2.1.3m]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 4ff5b53ff8a1d6232e21a3e8f0538dc87ca4920b Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sun, 20 Mar 2011 19:43:06 +0000 Subject: Client will now try to reconnect if no push reply received within handshake-window seconds. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7066 e7ae566f-a301-0410-adde-c780ea21d3b5 --- common.h | 5 +++++ forward.c | 4 ++-- openvpn.h | 1 + push.c | 13 ++++++++++++- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/common.h b/common.h index 5548f7c..0ca7323 100644 --- a/common.h +++ b/common.h @@ -86,6 +86,11 @@ typedef unsigned long ptr_type; */ #define PUSH_BUNDLE_SIZE 1024 +/* + * In how many seconds does client re-send PUSH_REQUEST if we haven't yet received a reply + */ +#define PUSH_REQUEST_INTERVAL 5 + /* * A sort of pseudo-filename for data provided inline within * the configuration file. diff --git a/forward.c b/forward.c index 65b8f0c..7212db4 100644 --- a/forward.c +++ b/forward.c @@ -178,8 +178,8 @@ check_push_request_dowork (struct context *c) { send_push_request (c); - /* if no response to first push_request, retry at 5 second intervals */ - event_timeout_modify_wakeup (&c->c2.push_request_interval, 5); + /* if no response to first push_request, retry at PUSH_REQUEST_INTERVAL second intervals */ + event_timeout_modify_wakeup (&c->c2.push_request_interval, PUSH_REQUEST_INTERVAL); } #endif /* P2MP */ diff --git a/openvpn.h b/openvpn.h index 47c9734..0ee439c 100644 --- a/openvpn.h +++ b/openvpn.h @@ -431,6 +431,7 @@ struct context_2 #endif struct event_timeout push_request_interval; + int n_sent_push_requests; bool did_pre_pull_restore; /* hash of pulled options, so we can compare when options change */ diff --git a/push.c b/push.c index 2e8aa55..ece3121 100644 --- a/push.c +++ b/push.c @@ -189,7 +189,18 @@ incoming_push_message (struct context *c, const struct buffer *buffer) bool send_push_request (struct context *c) { - return send_control_channel_string (c, "PUSH_REQUEST", D_PUSH); + const int max_push_requests = c->options.handshake_window / PUSH_REQUEST_INTERVAL; + if (++c->c2.n_sent_push_requests <= max_push_requests) + { + return send_control_channel_string (c, "PUSH_REQUEST", D_PUSH); + } + else + { + msg (D_STREAM_ERRORS, "No reply from server after sending %d push requests", max_push_requests); + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ + c->sig->signal_text = "no-push-reply"; + return false; + } } #if P2MP_SERVER -- cgit v1.2.3 From 5d2e139852c5e89b592ccae746743efe9c3f61d3 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Mon, 21 Mar 2011 09:00:39 +0000 Subject: Version 2.1.3n git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7069 e7ae566f-a301-0410-adde-c780ea21d3b5 --- version.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.m4 b/version.m4 index f3e7a8d..56feed2 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3m]) +define(PRODUCT_VERSION,[2.1.3n]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 1f001994070267d9d9016f0e5f13302de31e1284 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Fri, 25 Mar 2011 11:06:16 +0000 Subject: win/sign.py now accepts an optional tap-dir argument. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7086 e7ae566f-a301-0410-adde-c780ea21d3b5 --- win/sign.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/win/sign.py b/win/sign.py index ee4ae72..9376951 100644 --- a/win/sign.py +++ b/win/sign.py @@ -4,16 +4,20 @@ from wb import config, choose_arch, home_fn if 'SIGNTOOL' in config: sys.path.append(home_fn(config['SIGNTOOL'])) -def main(conf, arch): +def main(conf, arch, tap_dir): from signtool import SignTool - st = SignTool(conf) + st = SignTool(conf, tap_dir) for x64 in choose_arch(arch): st.sign_verify(x64=x64) # if we are run directly, and not loaded as a module if __name__ == "__main__": if len(sys.argv) >= 2: - main(config, sys.argv[1]) + if len(sys.argv) >= 3: + tap_dir = home_fn(sys.argv[2]) + else: + tap_dir = None + main(config, sys.argv[1], tap_dir) else: - print "usage: sign " + print "usage: sign [tap-dir]" sys.exit(2) -- cgit v1.2.3 From 0db046f253e86a3dd7583e2f7a13b21e7eba7493 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sat, 26 Mar 2011 21:16:40 +0000 Subject: Added "auth-token" client directive, which is intended to be pushed by server, and that is used to offer a temporary session token to clients that can be used in place of a password on subsequent credential challenges. This accomplishes the security benefit of preventing caching of the real password while offering most of the advantages of password caching, i.e. not forcing the user to re-enter credentials for every TLS renegotiation or network hiccup. auth-token does two things: 1. if password caching is enabled, the token replaces the previous password, and 2. if the management interface is active, the token is output to it: >PASSWORD:Auth-Token: Also made a minor change to HALT/RESTART processing when password caching is enabled. When client receives a HALT or RESTART message, and if the message text contains a flags block (i.e. [FFF]:message), if flag 'P' (preserve auth) is present in flags, don't purge the Auth password. Otherwise do purge the Auth password. Version 2.1.3o git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7088 e7ae566f-a301-0410-adde-c780ea21d3b5 --- forward.c | 5 +++-- init.c | 2 +- manage.c | 10 ++++++++-- manage.h | 5 +++++ misc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ misc.h | 4 ++++ options.c | 9 +++++++++ push.c | 24 +++++++++++++++++++++--- ssl.c | 18 +++++++++++++++--- ssl.h | 3 ++- version.m4 | 2 +- 11 files changed, 113 insertions(+), 13 deletions(-) diff --git a/forward.c b/forward.c index 7212db4..90b7d9f 100644 --- a/forward.c +++ b/forward.c @@ -232,8 +232,8 @@ bool send_control_channel_string (struct context *c, const char *str, int msglevel) { #if defined(USE_CRYPTO) && defined(USE_SSL) - if (c->c2.tls_multi) { + struct gc_arena gc = gc_new (); bool stat; /* buffered cleartext write onto TLS control channel */ @@ -250,9 +250,10 @@ send_control_channel_string (struct context *c, const char *str, int msglevel) msg (msglevel, "SENT CONTROL [%s]: '%s' (status=%d)", tls_common_name (c->c2.tls_multi, false), - str, + sanitize_control_message (str, &gc), (int) stat); + gc_free (&gc); return stat; } #endif diff --git a/init.c b/init.c index d0a1baa..7738f00 100644 --- a/init.c +++ b/init.c @@ -1929,7 +1929,7 @@ do_init_crypto_tls_c1 (struct context *c) msg (M_FATAL, "Error: private key password verification failed"); break; case AR_INTERACT: - ssl_purge_auth (); + ssl_purge_auth (false); case AR_NOINTERACT: c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Password failure error */ break; diff --git a/manage.c b/manage.c index 67f87d6..a79a8fd 100644 --- a/manage.c +++ b/manage.c @@ -698,7 +698,7 @@ static void man_forget_passwords (struct management *man) { #if defined(USE_CRYPTO) && defined(USE_SSL) - ssl_purge_auth (); + ssl_purge_auth (false); msg (M_CLIENT, "SUCCESS: Passwords were forgotten"); #endif } @@ -1682,7 +1682,7 @@ man_reset_client_socket (struct management *man, const bool exiting) { #if defined(USE_CRYPTO) && defined(USE_SSL) if (man->settings.flags & MF_FORGET_DISCONNECT) - ssl_purge_auth (); + ssl_purge_auth (false); #endif if (man->settings.flags & MF_SIGNAL) { int mysig = man_mod_signal (man, SIGUSR1); @@ -2515,6 +2515,12 @@ management_auth_failure (struct management *man, const char *type, const char *r msg (M_CLIENT, ">PASSWORD:Verification Failed: '%s'", type); } +void +management_auth_token (struct management *man, const char *token) +{ + msg (M_CLIENT, ">PASSWORD:Auth-Token:%s", token); +} + static inline bool man_persist_state (unsigned int *persistent, const int n) { diff --git a/manage.h b/manage.h index 5e0696b..c6ce31e 100644 --- a/manage.h +++ b/manage.h @@ -471,6 +471,11 @@ void management_echo (struct management *man, const char *string, const bool pul void management_auth_failure (struct management *man, const char *type, const char *reason); +/* + * Echo an authentication token to management interface + */ +void management_auth_token (struct management *man, const char *token); + /* * These functions drive the bytecount in/out counters. */ diff --git a/misc.c b/misc.c index 0f9dfcc..4a80004 100644 --- a/misc.c +++ b/misc.c @@ -1695,6 +1695,16 @@ purge_user_pass (struct user_pass *up, const bool force) } } +void +set_auth_token (struct user_pass *up, const char *token) +{ + if (token && strlen(token) && up && up->defined && !up->nocache) + { + CLEAR (up->password); + strncpynt (up->password, token, USER_PASS_LEN); + } +} + /* * Process string received by untrusted peer before * printing to console or log file. @@ -2363,3 +2373,37 @@ openvpn_basename (const char *path) } return NULL; } + +/* + * Remove SESS_ID_x strings (i.e. auth tokens) from control message + * strings so that they will not be output to log file. + */ +const char * +sanitize_control_message(const char *str, struct gc_arena *gc) +{ + char *ret = gc_malloc (strlen(str)+1, false, gc); + char *cp = ret; + bool redact = false; + + strcpy(ret, str); + for (;;) + { + const char c = *cp; + if (c == '\0') + break; + if (c == 'S' && !strncmp(cp, "SESS_ID_", 8)) + { + cp += 7; + redact = true; + } + else + { + if (c == ',') /* end of session id? */ + redact = false; + if (redact) + *cp = '_'; + } + ++cp; + } + return ret; +} diff --git a/misc.h b/misc.h index 3cd7d9e..cc6745a 100644 --- a/misc.h +++ b/misc.h @@ -306,6 +306,8 @@ void fail_user_pass (const char *prefix, void purge_user_pass (struct user_pass *up, const bool force); +void set_auth_token (struct user_pass *up, const char *token); + /* * Process string received by untrusted peer before * printing to console or log file. @@ -327,6 +329,8 @@ void openvpn_sleep (const int n); void configure_path (void); +const char *sanitize_control_message(const char *str, struct gc_arena *gc); + #if AUTO_USERID void get_user_pass_auto_userid (struct user_pass *up, const char *tag); #endif diff --git a/options.c b/options.c index 8ace13f..32ea07f 100644 --- a/options.c +++ b/options.c @@ -5802,6 +5802,15 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); ssl_set_auth_nocache (); } + else if (streq (p[0], "auth-token") && p[1]) + { + VERIFY_PERMISSION (OPT_P_ECHO); + ssl_set_auth_token(p[1]); +#ifdef ENABLE_MANAGEMENT + if (management) + management_auth_token (management, p[1]); +#endif + } else if (streq (p[0], "single-session")) { VERIFY_PERMISSION (OPT_P_GENERAL); diff --git a/push.c b/push.c index ece3121..339478a 100644 --- a/push.c +++ b/push.c @@ -52,7 +52,7 @@ receive_auth_failed (struct context *c, const struct buffer *buffer) c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ break; case AR_INTERACT: - ssl_purge_auth (); + ssl_purge_auth (false); case AR_NOINTERACT: c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ break; @@ -95,6 +95,24 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool const char *m = ""; if (buf_advance (&buf, adv) && buf_read_u8 (&buf) == ',' && BLEN (&buf)) m = BSTR (&buf); + + /* preserve cached passwords? */ + { + bool purge = true; + + if (m[0] == '[') + { + int i; + for (i = 1; m[i] != '\0' && m[i] != ']'; ++i) + { + if (m[i] == 'P') + purge = false; + } + } + if (purge) + ssl_purge_auth (true); + } + if (restart) { msg (D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m); @@ -166,7 +184,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer) unsigned int option_types_found = 0; int status; - msg (D_PUSH, "PUSH: Received control message: '%s'", BSTR (buffer)); + msg (D_PUSH, "PUSH: Received control message: '%s'", sanitize_control_message(BSTR(buffer), &gc)); status = process_incoming_push_msg (c, buffer, @@ -175,7 +193,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer) &option_types_found); if (status == PUSH_MSG_ERROR) - msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", BSTR (buffer)); + msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) { if (status == PUSH_MSG_REPLY) diff --git a/ssl.c b/ssl.c index dbc65eb..d5fe5ba 100644 --- a/ssl.c +++ b/ssl.c @@ -317,16 +317,28 @@ ssl_set_auth_nocache (void) auth_user_pass.nocache = true; } +/* + * Set an authentication token + */ +void +ssl_set_auth_token (const char *token) +{ + set_auth_token (&auth_user_pass, token); +} + /* * Forget private key password AND auth-user-pass username/password. */ void -ssl_purge_auth (void) +ssl_purge_auth (const bool auth_user_pass_only) { + if (!auth_user_pass_only) + { #ifdef USE_PKCS11 - pkcs11_logout (); + pkcs11_logout (); #endif - purge_user_pass (&passbuf, true); + purge_user_pass (&passbuf, true); + } purge_user_pass (&auth_user_pass, true); #ifdef ENABLE_CLIENT_CR ssl_purge_auth_challenge(); diff --git a/ssl.h b/ssl.h index eb059cc..82d9c12 100644 --- a/ssl.h +++ b/ssl.h @@ -722,7 +722,8 @@ void pem_password_setup (const char *auth_file); int pem_password_callback (char *buf, int size, int rwflag, void *u); void auth_user_pass_setup (const char *auth_file); void ssl_set_auth_nocache (void); -void ssl_purge_auth (void); +void ssl_set_auth_token (const char *token); +void ssl_purge_auth (const bool auth_user_pass_only); #ifdef ENABLE_CLIENT_CR diff --git a/version.m4 b/version.m4 index 56feed2..cd7ba56 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3n]) +define(PRODUCT_VERSION,[2.1.3o]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From e9f8696f3981fc493501082d996340c9021919c7 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sun, 27 Mar 2011 09:20:13 +0000 Subject: Added ./configure --enable-osxipconfig option for Mac OS X which will enable the use of ipconfig (instead of ifconfig) for configuring the IP address and netmask of the tun/tap adapter. Version 2.1.3p git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7092 e7ae566f-a301-0410-adde-c780ea21d3b5 --- configure.ac | 5 +++++ tun.c | 21 ++++++++++++++++++++- version.m4 | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 729ce40..342074f 100644 --- a/configure.ac +++ b/configure.ac @@ -176,6 +176,11 @@ AC_ARG_ENABLE(iproute2, test $enableval = "yes" && AC_DEFINE(CONFIG_FEATURE_IPROUTE, 1, [enable iproute2 support]) ) +AC_ARG_ENABLE(osxipconfig, + [ --enable-osxipconfig Enable support for ipconfig on OS X], + test $enableval = "yes" && AC_DEFINE(DARWIN_USE_IPCONFIG, 1, [Enable support for ipconfig on OS X]) +) + AC_ARG_ENABLE(def-auth, [ --disable-def-auth Disable deferred authentication], [DEF_AUTH="$enableval"], diff --git a/tun.c b/tun.c index 11c4204..8c94f89 100644 --- a/tun.c +++ b/tun.c @@ -786,7 +786,24 @@ do_ifconfig (struct tuntap *tt, tt->did_ifconfig = true; #elif defined(TARGET_DARWIN) - +#ifdef DARWIN_USE_IPCONFIG + if (tun) + { + msg (M_FATAL, "Error: tun point-to-point mode not supported on Darwin when DARWIN_USE_IPCONFIG is defined"); + } + else + { + argv_printf (&argv, + "/usr/sbin/ipconfig set %s MANUAL %s %s", + actual, + ifconfig_local, + ifconfig_remote_netmask + ); + } + argv_msg (M_INFO, &argv); + openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ipconfig failed"); + tt->did_ifconfig = true; +#else /* * Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD... */ @@ -832,9 +849,11 @@ do_ifconfig (struct tuntap *tt, tun_mtu ); } + argv_msg (M_INFO, &argv); openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ifconfig failed"); tt->did_ifconfig = true; +#endif /* Add a network route for the local tun interface */ if (!tun && tt->topology == TOP_SUBNET) diff --git a/version.m4 b/version.m4 index cd7ba56..f8b3b8d 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3o]) +define(PRODUCT_VERSION,[2.1.3p]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From ac1310528a248c99e039e7afaf48724ad1b7f10e Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 31 Mar 2011 23:18:06 +0000 Subject: Added more packet ID debug info at debug level 3 for debugging false positive packet replays. Version 2.1.3q. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7109 e7ae566f-a301-0410-adde-c780ea21d3b5 --- errlevel.h | 6 +-- init.c | 2 +- packet_id.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- packet_id.h | 7 ++- ssl.c | 6 ++- version.m4 | 2 +- 6 files changed, 142 insertions(+), 28 deletions(-) diff --git a/errlevel.h b/errlevel.h index 13a7114..be1ef5e 100644 --- a/errlevel.h +++ b/errlevel.h @@ -83,7 +83,7 @@ #define D_RESTART LOGLEV(3, 33, 0) /* show certain restart messages */ #define D_PUSH LOGLEV(3, 34, 0) /* show push/pull info */ #define D_IFCONFIG_POOL LOGLEV(3, 35, 0) /* show ifconfig pool info */ -#define D_BACKTRACK LOGLEV(3, 36, 0) /* show replay backtracks */ +#define D_PID_DEBUG_LOW LOGLEV(3, 36, 0) /* show low-freq packet-id debugging info */ #define D_AUTH LOGLEV(3, 37, 0) /* show user/pass auth info */ #define D_MULTI_LOW LOGLEV(3, 38, 0) /* show point-to-multipoint low-freq debug info */ #define D_PLUGIN LOGLEV(3, 39, 0) /* show plugin calls */ @@ -107,6 +107,7 @@ #define D_INIT_MEDIUM LOGLEV(4, 60, 0) /* show medium frequency init messages */ #define D_MTU_INFO LOGLEV(4, 61, 0) /* show terse MTU info */ #define D_SHOW_OCC_HASH LOGLEV(4, 62, 0) /* show MD5 hash of option compatibility string */ +#define D_PID_DEBUG_MEDIUM LOGLEV(4, 63, 0) /* show medium-freq packet-id debugging info */ #define D_LOG_RW LOGLEV(5, 0, 0) /* Print 'R' or 'W' to stdout for read/write */ @@ -121,7 +122,6 @@ #define D_FRAG_DEBUG LOGLEV(7, 70, M_DEBUG) /* show fragment debugging info */ #define D_WIN32_IO_LOW LOGLEV(7, 70, M_DEBUG) /* low freq win32 I/O debugging info */ #define D_MTU_DEBUG LOGLEV(7, 70, M_DEBUG) /* show MTU debugging info */ -#define D_PID_DEBUG_LOW LOGLEV(7, 70, M_DEBUG) /* show low-freq packet-id debugging info */ #define D_MULTI_DEBUG LOGLEV(7, 70, M_DEBUG) /* show medium-freq multi debugging info */ #define D_MSS LOGLEV(7, 70, M_DEBUG) /* show MSS adjustments */ #define D_COMP_LOW LOGLEV(7, 70, M_DEBUG) /* show adaptive compression state changes */ @@ -145,6 +145,7 @@ #define D_TLS_KEYSELECT LOGLEV(7, 70, M_DEBUG) /* show information on key selection for data channel */ #define D_ARGV_PARSE_CMD LOGLEV(7, 70, M_DEBUG) /* show parse_line() errors in argv_printf %sc */ #define D_CRYPTO_DEBUG LOGLEV(7, 70, M_DEBUG) /* show detailed info from crypto.c routines */ +#define D_PID_DEBUG LOGLEV(7, 70, M_DEBUG) /* show packet-id debugging info */ #define D_PF_DROPPED_BCAST LOGLEV(7, 71, M_DEBUG) /* packet filter dropped a broadcast packet */ #define D_PF_DEBUG LOGLEV(7, 72, M_DEBUG) /* packet filter debugging, must also define PF_DEBUG in pf.h */ @@ -162,7 +163,6 @@ #define D_READ_WRITE LOGLEV(9, 70, M_DEBUG) /* show all tun/tcp/udp reads/writes/opens */ #define D_PACKET_CONTENT LOGLEV(9, 70, M_DEBUG) /* show before/after encryption packet content */ #define D_TLS_NO_SEND_KEY LOGLEV(9, 70, M_DEBUG) /* show when no data channel send-key exists */ -#define D_PID_DEBUG LOGLEV(9, 70, M_DEBUG) /* show packet-id debugging info */ #define D_PID_PERSIST_DEBUG LOGLEV(9, 70, M_DEBUG) /* show packet-id persist debugging info */ #define D_LINK_RW_VERBOSE LOGLEV(9, 70, M_DEBUG) /* show link reads/writes with greater verbosity */ #define D_STREAM_DEBUG LOGLEV(9, 70, M_DEBUG) /* show TCP stream debug info */ diff --git a/init.c b/init.c index 7738f00..a1a1a8f 100644 --- a/init.c +++ b/init.c @@ -1833,7 +1833,7 @@ do_init_crypto_static (struct context *c, const unsigned int flags) if (options->replay) { packet_id_init (&c->c2.packet_id, options->replay_window, - options->replay_time); + options->replay_time, "STATIC", 0); c->c2.crypto_options.packet_id = &c->c2.packet_id; c->c2.crypto_options.pid_persist = &c->c1.pid_persist; c->c2.crypto_options.flags |= CO_PACKET_ID_LONG_FORM; diff --git a/packet_id.c b/packet_id.c index b11e71f..f38c121 100644 --- a/packet_id.c +++ b/packet_id.c @@ -41,6 +41,8 @@ #include "memdbg.h" +/* #define PID_SIMULATE_BACKTRACK */ + /* * Special time_t value that indicates that * sequence number has expired. @@ -48,16 +50,37 @@ #define SEQ_UNSEEN ((time_t)0) #define SEQ_EXPIRED ((time_t)1) +static void packet_id_debug_print (int msglevel, + const struct packet_id_rec *p, + const struct packet_id_net *pin, + const char *message, + int value); + +static inline void +packet_id_debug (int msglevel, + const struct packet_id_rec *p, + const struct packet_id_net *pin, + const char *message, + int value) +{ +#ifdef ENABLE_DEBUG + if (unlikely(check_debug_level(msglevel))) + packet_id_debug_print (msglevel, p, pin, message, value); +#endif +} + void -packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack) +packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit) { - dmsg (D_PID_DEBUG_LOW, "PID packet_id_init seq_backtrack=%d time_backtrack=%d", - seq_backtrack, - time_backtrack); + dmsg (D_PID_DEBUG, "PID packet_id_init seq_backtrack=%d time_backtrack=%d", + seq_backtrack, + time_backtrack); ASSERT (p); CLEAR (*p); + p->rec.name = name; + p->rec.unit = unit; if (seq_backtrack) { ASSERT (MIN_SEQ_BACKTRACK <= seq_backtrack && seq_backtrack <= MAX_SEQ_BACKTRACK); @@ -74,7 +97,7 @@ packet_id_free (struct packet_id *p) { if (p) { - dmsg (D_PID_DEBUG_LOW, "PID packet_id_free"); + dmsg (D_PID_DEBUG, "PID packet_id_free"); if (p->rec.seq_list) free (p->rec.seq_list); CLEAR (*p); @@ -105,7 +128,11 @@ packet_id_add (struct packet_id_rec *p, const struct packet_id_net *pin) CIRC_LIST_RESET (p->seq_list); } - while (p->id < pin->id) + while (p->id < pin->id +#ifdef PID_SIMULATE_BACKTRACK + || (get_random() % 64) < 31 +#endif + ) { CIRC_LIST_PUSH (p->seq_list, SEQ_UNSEEN); ++p->id; @@ -155,17 +182,13 @@ packet_id_reap (struct packet_id_rec *p) * it is a replay. */ bool -packet_id_test (const struct packet_id_rec *p, +packet_id_test (struct packet_id_rec *p, const struct packet_id_net *pin) { - static int max_backtrack_stat; packet_id_type diff; - dmsg (D_PID_DEBUG, - "PID TEST " time_format ":" packet_id_format " " time_format ":" packet_id_format "", - (time_type)p->time, (packet_id_print_type)p->id, (time_type)pin->time, - (packet_id_print_type)pin->id); - + packet_id_debug (D_PID_DEBUG, p, pin, "PID_TEST", 0); + ASSERT (p->initialized); if (!pin->id) @@ -189,19 +212,35 @@ packet_id_test (const struct packet_id_rec *p, diff = p->id - pin->id; /* keep track of maximum backtrack seen for debugging purposes */ - if ((int)diff > max_backtrack_stat) + if ((int)diff > p->max_backtrack_stat) { - max_backtrack_stat = (int)diff; - msg (D_BACKTRACK, "Replay-window backtrack occurred [%d]", max_backtrack_stat); + p->max_backtrack_stat = (int)diff; + packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR replay-window backtrack occurred", p->max_backtrack_stat); } if (diff >= (packet_id_type) CIRC_LIST_SIZE (p->seq_list)) - return false; + { + packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR large diff", diff); + return false; + } - return CIRC_LIST_ITEM (p->seq_list, diff) == 0; + { + const time_t v = CIRC_LIST_ITEM (p->seq_list, diff); + if (v == 0) + return true; + else + { + /* might want to increase this to D_PID_DEBUG_MEDIUM (or even D_PID_DEBUG) in the future */ + packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR replay", diff); + return false; + } + } } else if (pin->time < p->time) /* if time goes back, reject */ - return false; + { + packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR time backtrack", 0); + return false; + } else /* time moved forward */ return true; } @@ -434,6 +473,76 @@ packet_id_persist_print (const struct packet_id_persist *p, struct gc_arena *gc) return (char *)out.data; } +#ifdef ENABLE_DEBUG + +static void +packet_id_debug_print (int msglevel, + const struct packet_id_rec *p, + const struct packet_id_net *pin, + const char *message, + int value) +{ + struct gc_arena gc = gc_new (); + struct buffer out = alloc_buf_gc (256, &gc); + struct timeval tv; + const time_t prev_now = now; + const struct seq_list *sl = p->seq_list; + int i; + + CLEAR (tv); + gettimeofday (&tv, NULL); + + buf_printf (&out, "%s [%d]", message, value); + buf_printf (&out, " [%s-%d] [", p->name, p->unit); + for (i = 0; i < sl->x_size; ++i) + { + char c; + time_t v; + int diff; + + v = CIRC_LIST_ITEM(sl, i); + if (v == SEQ_UNSEEN) + c = '_'; + else if (v == SEQ_EXPIRED) + c = 'E'; + else + { + diff = (int) prev_now - v; + if (diff < 0) + c = 'N'; + else if (diff < 10) + c = '0' + diff; + else + c = '>'; + } + buf_printf(&out, "%c", c); + } + buf_printf (&out, "] " time_format ":" packet_id_format, (time_type)p->time, (packet_id_print_type)p->id); + if (pin) + buf_printf (&out, " " time_format ":" packet_id_format, (time_type)pin->time, (packet_id_print_type)pin->id); + + buf_printf (&out, " t=" time_format "[%d]", + (time_type)prev_now, + (int)(prev_now - tv.tv_sec)); + + buf_printf (&out, " r=[%d,%d,%d,%d,%d]", + (int)(p->last_reap - tv.tv_sec), + p->seq_backtrack, + p->time_backtrack, + p->max_backtrack_stat, + (int)p->initialized); + buf_printf (&out, " sl=[%d,%d,%d,%d]", + sl->x_head, + sl->x_size, + sl->x_cap, + sl->x_sizeof); + + msg (msglevel, "%s", BSTR(&out)); + gc_free (&gc); +} + +#endif + #ifdef PID_TEST void diff --git a/packet_id.h b/packet_id.h index 12c1df3..1c341f7 100644 --- a/packet_id.h +++ b/packet_id.h @@ -138,8 +138,11 @@ struct packet_id_rec packet_id_type id; /* highest sequence number received */ int seq_backtrack; /* set from --replay-window */ int time_backtrack; /* set from --replay-window */ + int max_backtrack_stat; /* maximum backtrack seen so far */ bool initialized; /* true if packet_id_init was called */ struct seq_list *seq_list; /* packet-id "memory" */ + const char *name; + int unit; }; /* @@ -207,11 +210,11 @@ struct packet_id struct packet_id_rec rec; }; -void packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack); +void packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit); void packet_id_free (struct packet_id *p); /* should we accept an incoming packet id ? */ -bool packet_id_test (const struct packet_id_rec *p, +bool packet_id_test (struct packet_id_rec *p, const struct packet_id_net *pin); /* change our current state to reflect an accepted packet id */ diff --git a/ssl.c b/ssl.c index d5fe5ba..bbb9701 100644 --- a/ssl.c +++ b/ssl.c @@ -2644,7 +2644,8 @@ key_state_init (struct tls_session *session, struct key_state *ks) /* init packet ID tracker */ packet_id_init (&ks->packet_id, session->opt->replay_window, - session->opt->replay_time); + session->opt->replay_time, + "SSL", ks->key_id); #ifdef MANAGEMENT_DEF_AUTH ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++; @@ -2749,7 +2750,8 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session) /* initialize packet ID replay window for --tls-auth */ packet_id_init (session->tls_auth.packet_id, session->opt->replay_window, - session->opt->replay_time); + session->opt->replay_time, + "TLS_AUTH", session->key_id); /* load most recent packet-id to replay protect on --tls-auth */ packet_id_persist_load_obj (session->tls_auth.pid_persist, session->tls_auth.packet_id); diff --git a/version.m4 b/version.m4 index f8b3b8d..b539d1a 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3p]) +define(PRODUCT_VERSION,[2.1.3q]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 4d453a1792b04f01a8c313157402ce0501ae809c Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sat, 2 Apr 2011 08:21:28 +0000 Subject: Fixed bug that incorrectly placed stricter TCP packet replay rules on UDP sessions when the client daemon was running in UDP/TCP adaptive mode, and transitioned from TCP to UDP. The bug would cause a single dropped packet in UDP mode to trigger a barrage of packet replay errors followed by a disconnect and reconnect. Version 2.1.3r git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7125 e7ae566f-a301-0410-adde-c780ea21d3b5 --- init.c | 15 ++++++--------- packet_id.c | 7 ++++--- packet_id.h | 2 +- ssl.c | 2 ++ ssl.h | 1 + version.m4 | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/init.c b/init.c index a1a1a8f..ef09e8e 100644 --- a/init.c +++ b/init.c @@ -102,13 +102,6 @@ update_options_ce_post (struct options *options) options->ping_rec_timeout_action = PING_RESTART; } #endif -#ifdef USE_CRYPTO - /* - * Don't use replay window for TCP mode (i.e. require that packets be strictly in sequence). - */ - if (link_socket_proto_connection_oriented (options->ce.proto)) - options->replay_window = options->replay_time = 0; -#endif } #if HTTP_PROXY_FALLBACK @@ -1832,8 +1825,11 @@ do_init_crypto_static (struct context *c, const unsigned int flags) /* Initialize packet ID tracking */ if (options->replay) { - packet_id_init (&c->c2.packet_id, options->replay_window, - options->replay_time, "STATIC", 0); + packet_id_init (&c->c2.packet_id, + link_socket_proto_connection_oriented (options->ce.proto), + options->replay_window, + options->replay_time, + "STATIC", 0); c->c2.crypto_options.packet_id = &c->c2.packet_id; c->c2.crypto_options.pid_persist = &c->c1.pid_persist; c->c2.crypto_options.flags |= CO_PACKET_ID_LONG_FORM; @@ -2034,6 +2030,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.replay = options->replay; to.replay_window = options->replay_window; to.replay_time = options->replay_time; + to.tcp_mode = link_socket_proto_connection_oriented (options->ce.proto); to.transition_window = options->transition_window; to.handshake_window = options->handshake_window; to.packet_timeout = options->tls_timeout; diff --git a/packet_id.c b/packet_id.c index f38c121..9bbfbf3 100644 --- a/packet_id.c +++ b/packet_id.c @@ -70,9 +70,10 @@ packet_id_debug (int msglevel, } void -packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit) +packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_backtrack, const char *name, int unit) { - dmsg (D_PID_DEBUG, "PID packet_id_init seq_backtrack=%d time_backtrack=%d", + dmsg (D_PID_DEBUG, "PID packet_id_init tcp_mode=%d seq_backtrack=%d time_backtrack=%d", + tcp_mode, seq_backtrack, time_backtrack); @@ -81,7 +82,7 @@ packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, cons p->rec.name = name; p->rec.unit = unit; - if (seq_backtrack) + if (seq_backtrack && !tcp_mode) { ASSERT (MIN_SEQ_BACKTRACK <= seq_backtrack && seq_backtrack <= MAX_SEQ_BACKTRACK); ASSERT (MIN_TIME_BACKTRACK <= time_backtrack && time_backtrack <= MAX_TIME_BACKTRACK); diff --git a/packet_id.h b/packet_id.h index 1c341f7..7f4be8a 100644 --- a/packet_id.h +++ b/packet_id.h @@ -210,7 +210,7 @@ struct packet_id struct packet_id_rec rec; }; -void packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit); +void packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_backtrack, const char *name, int unit); void packet_id_free (struct packet_id *p); /* should we accept an incoming packet id ? */ diff --git a/ssl.c b/ssl.c index bbb9701..572d8e2 100644 --- a/ssl.c +++ b/ssl.c @@ -2643,6 +2643,7 @@ key_state_init (struct tls_session *session, struct key_state *ks) /* init packet ID tracker */ packet_id_init (&ks->packet_id, + session->opt->tcp_mode, session->opt->replay_window, session->opt->replay_time, "SSL", ks->key_id); @@ -2749,6 +2750,7 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session) /* initialize packet ID replay window for --tls-auth */ packet_id_init (session->tls_auth.packet_id, + session->opt->tcp_mode, session->opt->replay_window, session->opt->replay_time, "TLS_AUTH", session->key_id); diff --git a/ssl.h b/ssl.h index 82d9c12..eca3922 100644 --- a/ssl.h +++ b/ssl.h @@ -477,6 +477,7 @@ struct tls_options int replay_window; /* --replay-window parm */ int replay_time; /* --replay-window parm */ + bool tcp_mode; /* packet authentication for TLS handshake */ struct crypto_options tls_auth; diff --git a/version.m4 b/version.m4 index b539d1a..97447b7 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3q]) +define(PRODUCT_VERSION,[2.1.3r]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From 28c8776b65c2300b758cd2b707283a43b4a582e8 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sun, 3 Apr 2011 21:48:15 +0000 Subject: Fixed bug in port-share that could cause port share process to crash with output like this: TCP connection established with 85.190.0.3:41781 85.190.0.3:41781 SIGTERM[soft,port-share-redirect] received, client-instance exiting MANAGEMENT: TCP recv error: Socket operation on non-socket MANAGEMENT: Client disconnected MANAGEMENT: Triggering management exit Exiting due to fatal error EVENT: epoll_ctl EPOLL_CTL_MOD failed, sd=6: Bad file descriptor (errno=9) Then an error like this for every incoming connection that should be proxied: 76.120.71.74:55302 PORT SHARE: sendmsg failed -- unable to communicate with background process (6,8,-1,-1): Connection refused (errno=111) Version 2.1.3s git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7127 e7ae566f-a301-0410-adde-c780ea21d3b5 --- ps.c | 3 +++ version.m4 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ps.c b/ps.c index 5b1792a..4cdac3c 100644 --- a/ps.c +++ b/ps.c @@ -872,6 +872,9 @@ port_share_open (const char *host, /* Let msg know that we forked */ msg_forked (); + /* Don't interact with management interface */ + management = NULL; + /* close all parent fds except our socket back to parent */ close_fds_except (fd[1]); diff --git a/version.m4 b/version.m4 index 97447b7..12ce627 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3r]) +define(PRODUCT_VERSION,[2.1.3s]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From e51935df0ee3984a0464bfd72afc58836cb79d99 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Tue, 12 Apr 2011 05:14:34 +0000 Subject: For Mac OSX, when DARWIN_USE_IPCONFIG is defined, retry ipconfig command on failure once every second for up to 15 seconds. This is necessary to work around an issue observed on OSX 10.5 where the ipconfig command sometimes fails if executed immediately after the tun device open. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7151 e7ae566f-a301-0410-adde-c780ea21d3b5 --- tun.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tun.c b/tun.c index 8c94f89..f2dec25 100644 --- a/tun.c +++ b/tun.c @@ -801,7 +801,17 @@ do_ifconfig (struct tuntap *tt, ); } argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ipconfig failed"); + { + int i; + const int n = 15; + for (i = 1; i <= n; ++i) /* OSX 10.5 needs retry */ + { + if (openvpn_execve_check (&argv, es, (i == n) ? S_FATAL : 0, "Mac OS X ipconfig failed")) + break; + msg (M_INFO, "Retry #%d", i); + openvpn_sleep(1); + } + } tt->did_ifconfig = true; #else /* -- cgit v1.2.3 From cacae3c01c812a793b3e9635ac3cad6f11dbc880 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Tue, 12 Apr 2011 05:15:15 +0000 Subject: Version 2.1.3t git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7152 e7ae566f-a301-0410-adde-c780ea21d3b5 --- version.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.m4 b/version.m4 index 12ce627..8892283 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3s]) +define(PRODUCT_VERSION,[2.1.3t]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From cf906790a88cc4489fd4677aa6b9c5f6a7146488 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Tue, 19 Apr 2011 10:28:06 +0000 Subject: Revert r7092 and r7151, i.e. remove --enable-osxipconfig configure option. ipconfig on Mac has certain behavior that makes it unsuitable for use by OpenVPN to configure tun/tap interface. Version 2.1.3u git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7191 e7ae566f-a301-0410-adde-c780ea21d3b5 --- configure.ac | 5 ----- tun.c | 29 ----------------------------- version.m4 | 2 +- 3 files changed, 1 insertion(+), 35 deletions(-) diff --git a/configure.ac b/configure.ac index 342074f..729ce40 100644 --- a/configure.ac +++ b/configure.ac @@ -176,11 +176,6 @@ AC_ARG_ENABLE(iproute2, test $enableval = "yes" && AC_DEFINE(CONFIG_FEATURE_IPROUTE, 1, [enable iproute2 support]) ) -AC_ARG_ENABLE(osxipconfig, - [ --enable-osxipconfig Enable support for ipconfig on OS X], - test $enableval = "yes" && AC_DEFINE(DARWIN_USE_IPCONFIG, 1, [Enable support for ipconfig on OS X]) -) - AC_ARG_ENABLE(def-auth, [ --disable-def-auth Disable deferred authentication], [DEF_AUTH="$enableval"], diff --git a/tun.c b/tun.c index f2dec25..f1b132c 100644 --- a/tun.c +++ b/tun.c @@ -786,34 +786,6 @@ do_ifconfig (struct tuntap *tt, tt->did_ifconfig = true; #elif defined(TARGET_DARWIN) -#ifdef DARWIN_USE_IPCONFIG - if (tun) - { - msg (M_FATAL, "Error: tun point-to-point mode not supported on Darwin when DARWIN_USE_IPCONFIG is defined"); - } - else - { - argv_printf (&argv, - "/usr/sbin/ipconfig set %s MANUAL %s %s", - actual, - ifconfig_local, - ifconfig_remote_netmask - ); - } - argv_msg (M_INFO, &argv); - { - int i; - const int n = 15; - for (i = 1; i <= n; ++i) /* OSX 10.5 needs retry */ - { - if (openvpn_execve_check (&argv, es, (i == n) ? S_FATAL : 0, "Mac OS X ipconfig failed")) - break; - msg (M_INFO, "Retry #%d", i); - openvpn_sleep(1); - } - } - tt->did_ifconfig = true; -#else /* * Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD... */ @@ -863,7 +835,6 @@ do_ifconfig (struct tuntap *tt, argv_msg (M_INFO, &argv); openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ifconfig failed"); tt->did_ifconfig = true; -#endif /* Add a network route for the local tun interface */ if (!tun && tt->topology == TOP_SUBNET) diff --git a/version.m4 b/version.m4 index 8892283..85cd043 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3t]) +define(PRODUCT_VERSION,[2.1.3u]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From d5497262ae1d1a7cf50a45b5ab6750f63bf8565d Mon Sep 17 00:00:00 2001 From: James Yonan Date: Sun, 24 Apr 2011 00:59:28 +0000 Subject: Added 'dir' flag to "crl-verify" (see man page for info). Don't call SSL_CTX_set_client_CA_list or SSL_CTX_set_client_CA_list if not running in server mode (these functions are only useful for TLS/SSL servers). Modified openvpn_snprintf to return false on overflow, and true otherwise. When AUTH_FAILED,... is received, log the full string. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7213 e7ae566f-a301-0410-adde-c780ea21d3b5 --- buffer.c | 9 +++-- buffer.h | 2 +- openvpn.8 | 12 +++++- options.c | 4 +- push.c | 2 +- ssl.c | 127 ++++++++++++++++++++++++++++++++++++-------------------------- ssl.h | 1 + 7 files changed, 96 insertions(+), 61 deletions(-) diff --git a/buffer.c b/buffer.c index 2952767..5499d99 100644 --- a/buffer.c +++ b/buffer.c @@ -218,20 +218,21 @@ buf_printf (struct buffer *buf, const char *format, ...) /* * This is necessary due to certain buggy implementations of snprintf, * that don't guarantee null termination for size > 0. + * Return false on overflow. */ -int openvpn_snprintf(char *str, size_t size, const char *format, ...) +bool openvpn_snprintf(char *str, size_t size, const char *format, ...) { va_list arglist; - int ret = 0; + int len = -1; if (size > 0) { va_start (arglist, format); - ret = vsnprintf (str, size, format, arglist); + len = vsnprintf (str, size, format, arglist); va_end (arglist); str[size - 1] = 0; } - return ret; + return (len >= 0 && len < size); } /* diff --git a/buffer.h b/buffer.h index 0f22cda..58273e2 100644 --- a/buffer.h +++ b/buffer.h @@ -280,7 +280,7 @@ bool buf_printf (struct buffer *buf, const char *format, ...) /* * Like snprintf but guarantees null termination for size > 0 */ -int openvpn_snprintf(char *str, size_t size, const char *format, ...) +bool openvpn_snprintf(char *str, size_t size, const char *format, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 3, 4))) #endif diff --git a/openvpn.8 b/openvpn.8 index 037ba7e..1953b16 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -4457,7 +4457,7 @@ or .B --tls-verify. .\"********************************************************* .TP -.B --crl-verify crl +.B --crl-verify crl ['dir'] Check peer certificate against the file .B crl in PEM format. @@ -4473,6 +4473,16 @@ overall integrity of the PKI. The only time when it would be necessary to rebuild the entire PKI from scratch would be if the root certificate key itself was compromised. + +If the optional +.B dir +flag is specified, enable a different mode where +.B crl +is a directory containing files named as revoked serial numbers +(the files may be empty, the contents are never read). If a client +requests a connection, where the client certificate serial number +(decimal string) is the name of a file present in the directory, +it will be rejected. .\"********************************************************* .SS SSL Library information: .\"********************************************************* diff --git a/options.c b/options.c index 32ea07f..fd3fec6 100644 --- a/options.c +++ b/options.c @@ -534,7 +534,7 @@ static const char usage_message[] = " see --secret option for more info.\n" "--askpass [file]: Get PEM password from controlling tty before we daemonize.\n" "--auth-nocache : Don't cache --askpass or --auth-user-pass passwords.\n" - "--crl-verify crl: Check peer certificate against a CRL.\n" + "--crl-verify crl ['dir']: Check peer certificate against a CRL.\n" "--tls-verify cmd: Execute shell command cmd to verify the X509 name of a\n" " pending TLS connection that has otherwise passed all other\n" " tests of certification. cmd should return 0 to allow\n" @@ -5836,6 +5836,8 @@ add_option (struct options *options, else if (streq (p[0], "crl-verify") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); + if (p[2] && streq(p[2], "dir")) + options->ssl_flags |= SSLF_CRL_VERIFY_DIR; options->crl_file = p[1]; } else if (streq (p[0], "tls-verify") && p[1]) diff --git a/push.c b/push.c index 339478a..5b870ce 100644 --- a/push.c +++ b/push.c @@ -42,7 +42,7 @@ void receive_auth_failed (struct context *c, const struct buffer *buffer) { - msg (M_VERB0, "AUTH: Received AUTH_FAILED control message"); + msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); connection_list_set_no_advance(&c->options); if (c->options.pull) { diff --git a/ssl.c b/ssl.c index 572d8e2..095b6a6 100644 --- a/ssl.c +++ b/ssl.c @@ -836,6 +836,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) const struct tls_options *opt; const int max_depth = MAX_CERT_DEPTH; struct argv argv = argv_new (); + char *serial = NULL; /* get the tls_session pointer */ ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); @@ -929,14 +930,12 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) { ASN1_INTEGER *asn1_i; BIGNUM *bignum; - char *dec; asn1_i = X509_get_serialNumber(ctx->current_cert); bignum = ASN1_INTEGER_to_BN(asn1_i, NULL); - dec = BN_bn2dec(bignum); + serial = BN_bn2dec(bignum); openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", ctx->error_depth); - setenv_str (opt->es, envname, dec); + setenv_str (opt->es, envname, serial); BN_free(bignum); - OPENSSL_free(dec); } /* export current untrusted IP */ @@ -1060,67 +1059,89 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) /* check peer cert against CRL */ if (opt->crl_file) { - X509_CRL *crl=NULL; - X509_REVOKED *revoked; - BIO *in=NULL; - int n,i,retval = 0; + if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR) + { + char fn[256]; + int fd; + if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", opt->crl_file, OS_SPECIFIC_DIRSEP, serial)) + { + msg (D_HANDSHAKE, "VERIFY CRL: filename overflow"); + goto err; + } + fd = open (fn, O_RDONLY); + if (fd >= 0) + { + msg (D_HANDSHAKE, "VERIFY CRL: certificate serial number %s is revoked", serial); + close(fd); + goto err; + } + } + else + { + X509_CRL *crl=NULL; + X509_REVOKED *revoked; + BIO *in=NULL; + int n,i,retval = 0; - in=BIO_new(BIO_s_file()); + in=BIO_new(BIO_s_file()); - if (in == NULL) { - msg (M_ERR, "CRL: BIO err"); - goto end; - } - if (BIO_read_filename(in, opt->crl_file) <= 0) { - msg (M_ERR, "CRL: cannot read: %s", opt->crl_file); - goto end; - } - crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL); - if (crl == NULL) { - msg (M_ERR, "CRL: cannot read CRL from file %s", opt->crl_file); - goto end; - } + if (in == NULL) { + msg (M_ERR, "CRL: BIO err"); + goto end; + } + if (BIO_read_filename(in, opt->crl_file) <= 0) { + msg (M_ERR, "CRL: cannot read: %s", opt->crl_file); + goto end; + } + crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL); + if (crl == NULL) { + msg (M_ERR, "CRL: cannot read CRL from file %s", opt->crl_file); + goto end; + } - if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) { - msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", opt->crl_file, subject); - retval = 1; - goto end; - } + if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) { + msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", opt->crl_file, subject); + retval = 1; + goto end; + } - n = sk_num(X509_CRL_get_REVOKED(crl)); + n = sk_num(X509_CRL_get_REVOKED(crl)); - for (i = 0; i < n; i++) { - revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i); - if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) { - msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject); - goto end; - } - } + for (i = 0; i < n; i++) { + revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i); + if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) { + msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject); + goto end; + } + } - retval = 1; - msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject); + retval = 1; + msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject); - end: + end: - BIO_free(in); - if (crl) - X509_CRL_free (crl); - if (!retval) - goto err; + BIO_free(in); + if (crl) + X509_CRL_free (crl); + if (!retval) + goto err; + } } msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", ctx->error_depth, subject); - session->verified = true; + + done: OPENSSL_free (subject); + if (serial) + OPENSSL_free(serial); argv_reset (&argv); - return 1; /* Accept connection */ + return (session->verified == true) ? 1 : 0; err: ERR_clear_error (); - OPENSSL_free (subject); - argv_reset (&argv); - return 0; /* Reject connection */ + session->verified = false; + goto done; } void @@ -1954,7 +1975,7 @@ init_ssl (const struct options *options) { if (!X509_STORE_add_cert(ctx->cert_store,sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)"); - if (!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) + if (options->tls_server && !SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); } } @@ -2066,11 +2087,11 @@ init_ssl (const struct options *options) #endif { /* Load CA file for verifying peer supplied certificate */ - status = SSL_CTX_load_verify_locations (ctx, options->ca_file, options->ca_path); + status = SSL_CTX_load_verify_locations (ctx, options->ca_file, NULL); } if (!status) - msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", options->ca_file, options->ca_path); + msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", np(options->ca_file), np(options->ca_path)); /* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */ if (options->ca_path) { @@ -2094,7 +2115,7 @@ init_ssl (const struct options *options) } /* Load names of CAs from file and use it as a client CA list */ - if (options->ca_file) { + if (options->ca_file && options->tls_server) { STACK_OF(X509_NAME) *cert_names = NULL; #if ENABLE_INLINE_FILES if (!strcmp (options->ca_file, INLINE_FILE_TAG) && options->ca_file_inline) @@ -2108,7 +2129,7 @@ init_ssl (const struct options *options) } if (!cert_names) msg (M_SSLERR, "Cannot load CA certificate file %s (SSL_load_client_CA_file)", options->ca_file); - SSL_CTX_set_client_CA_list (ctx, cert_names); + SSL_CTX_set_client_CA_list (ctx, cert_names); } } diff --git a/ssl.h b/ssl.h index eca3922..fe494b1 100644 --- a/ssl.h +++ b/ssl.h @@ -504,6 +504,7 @@ struct tls_options # define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2) # define SSLF_NO_NAME_REMAPPING (1<<3) # define SSLF_OPT_VERIFY (1<<4) +# define SSLF_CRL_VERIFY_DIR (1<<5) unsigned int ssl_flags; #ifdef MANAGEMENT_DEF_AUTH -- cgit v1.2.3 From 7966d75a9d41453a56e41eaae7b0fd64f75f7ec3 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Mon, 25 Apr 2011 04:58:34 +0000 Subject: Added new "extra-certs" and "verify-hash" options (see man page for details). Increase the timeout after SIGUSR1 restart when restart is not due to server_poll_timeout. Version 2.1.3v git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7215 e7ae566f-a301-0410-adde-c780ea21d3b5 --- init.c | 3 +++ openvpn.8 | 27 +++++++++++++++++++++++++++ options.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ options.h | 3 +++ ssl.c | 41 +++++++++++++++++++++++++++++++++++++++++ ssl.h | 1 + version.m4 | 2 +- 7 files changed, 128 insertions(+), 1 deletion(-) diff --git a/init.c b/init.c index ef09e8e..b1f65a9 100644 --- a/init.c +++ b/init.c @@ -1706,8 +1706,10 @@ socket_restart_pause (struct context *c) if (auth_retry_get () == AR_NOINTERACT) sec = 10; +#if 0 /* not really needed because of c->persist.restart_sleep_seconds */ if (c->options.server_poll_timeout && sec > 1) sec = 1; +#endif #endif if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec) @@ -2057,6 +2059,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.ns_cert_type = options->ns_cert_type; memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku)); to.remote_cert_eku = options->remote_cert_eku; + to.verify_hash = options->verify_hash; to.es = c->c2.es; #ifdef ENABLE_DEBUG diff --git a/openvpn.8 b/openvpn.8 index 1953b16..85889de 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -3887,6 +3887,22 @@ that for certificate authority functions, you must set up the files ). .\"********************************************************* .TP +.B --extra-certs file +Specify a +.B file +containing one or more PEM certs (concatenated together) +that complete the +local certificate chain. + +This option is useful for "split" CAs, where the CA for server +certs is different than the CA for client certs. Putting certs +in this file allows them to be used to complete the local +certificate chain without trusting them to verify the peer-submitted +certificate, as would be the case if the certs were placed in the +.B ca +file. +.\"********************************************************* +.TP .B --key file Local peer's private key in .pem format. Use the private key which was generated when you built your peer's certificate (see @@ -3903,6 +3919,17 @@ and .B --key. .\"********************************************************* .TP +.B --verify-hash hash +Specify SHA1 fingerprint for level-1 cert. The level-1 cert is the +CA (or intermediate cert) that signs the leaf certificate, and is +one removed from the leaf certificate in the direction of the root. +When accepting a connection from a peer, the level-1 cert +fingerprint must match +.B hash +or certificate verification will fail. Hash is specified +as XX:XX:... For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16 +.\"********************************************************* +.TP .B --pkcs11-cert-private [0|1]... Set if access to certificate object should be performed after login. Every provider has its own setting. diff --git a/options.c b/options.c index fd3fec6..1cfccd3 100644 --- a/options.c +++ b/options.c @@ -507,9 +507,11 @@ static const char usage_message[] = " Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n" "--cert file : Local certificate in .pem format -- must be signed\n" " by a Certificate Authority in --ca file.\n" + "--extra-certs file : one or more PEM certs that complete the cert chain.\n" "--key file : Local private key in .pem format.\n" "--pkcs12 file : PKCS#12 file containing local private key, local certificate\n" " and optionally the root CA certificate.\n" + "--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n" #ifdef WIN32 "--cryptoapicert select-string : Load the certificate and private key from the\n" " Windows Certificate System Store.\n" @@ -894,6 +896,40 @@ is_stateful_restart (const struct options *o) return is_persist_option (o) || connection_list_defined (o); } +#ifdef USE_SSL +static uint8_t * +parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_arena *gc) +{ + int i; + const char *cp = str; + uint8_t *ret = (uint8_t *) gc_malloc (nbytes, true, gc); + char term = 1; + int byte; + char bs[3]; + + for (i = 0; i < nbytes; ++i) + { + if (strlen(cp) < 2) + msg (msglevel, "format error in hash fingerprint: %s", str); + bs[0] = *cp++; + bs[1] = *cp++; + bs[2] = 0; + byte = 0; + if (sscanf(bs, "%x", &byte) != 1) + msg (msglevel, "format error in hash fingerprint hex byte: %s", str); + ret[i] = (uint8_t)byte; + term = *cp++; + if (term != ':' && term != 0) + msg (msglevel, "format error in hash fingerprint delimiter: %s", str); + if (term == 0) + break; + } + if (term != 0 || i != nbytes-1) + msg (msglevel, "hash fingerprint is different length than expected (%d bytes): %s", nbytes, str); + return ret; +} +#endif + #ifdef WIN32 #ifdef ENABLE_DEBUG @@ -5758,6 +5794,22 @@ add_option (struct options *options, } #endif } + else if (streq (p[0], "extra-certs") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->extra_certs_file = p[1]; +#if ENABLE_INLINE_FILES + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + options->extra_certs_file_inline = p[2]; + } +#endif + } + else if (streq (p[0], "verify-hash") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc); + } #ifdef WIN32 else if (streq (p[0], "cryptoapicert") && p[1]) { diff --git a/options.h b/options.h index 74ba9d4..f0baabe 100644 --- a/options.h +++ b/options.h @@ -477,6 +477,7 @@ struct options const char *ca_path; const char *dh_file; const char *cert_file; + const char *extra_certs_file; const char *priv_key_file; const char *pkcs12_file; const char *cipher_list; @@ -487,6 +488,7 @@ struct options #if ENABLE_INLINE_FILES const char *ca_file_inline; const char *cert_file_inline; + const char *extra_certs_file_inline; char *priv_key_file_inline; const char *dh_file_inline; const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */ @@ -495,6 +497,7 @@ struct options int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */ unsigned remote_cert_ku[MAX_PARMS]; const char *remote_cert_eku; + uint8_t *verify_hash; #ifdef ENABLE_PKCS11 const char *pkcs11_providers[MAX_PARMS]; diff --git a/ssl.c b/ssl.c index 095b6a6..df237cc 100644 --- a/ssl.c +++ b/ssl.c @@ -910,6 +910,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) goto err; /* Reject connection */ } + /* verify level 1 cert, i.e. the CA that signed our leaf cert */ + if (ctx->error_depth == 1 && opt->verify_hash) + { + if (memcmp (ctx->current_cert->sha1_hash, opt->verify_hash, SHA_DIGEST_LENGTH)) + { + msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed"); + goto err; + } + } + /* save common name in session object */ if (ctx->error_depth == 0) set_common_name (session, common_name); @@ -2140,6 +2150,37 @@ init_ssl (const struct options *options) msg (M_SSLERR, "Cannot load certificate chain file %s (SSL_use_certificate_chain_file)", options->cert_file); } + /* Load extra certificates that are part of our own certificate + chain but shouldn't be included in the verify chain */ + if (options->extra_certs_file || options->extra_certs_file_inline) + { + BIO *bio; + X509 *cert; +#if ENABLE_INLINE_FILES + if (!strcmp (options->extra_certs_file, INLINE_FILE_TAG) && options->extra_certs_file_inline) + { + bio = BIO_new_mem_buf ((char *)options->extra_certs_file_inline, -1); + } + else +#endif + { + bio = BIO_new(BIO_s_file()); + if (BIO_read_filename(bio, options->extra_certs_file) <= 0) + msg (M_SSLERR, "Cannot load extra-certs file: %s", options->extra_certs_file); + } + for (;;) + { + cert = NULL; + if (!PEM_read_bio_X509 (bio, &cert, 0, NULL)) /* takes ownership of cert */ + break; + if (!cert) + msg (M_SSLERR, "Error reading extra-certs certificate"); + if (SSL_CTX_add_extra_chain_cert(ctx, cert) != 1) + msg (M_SSLERR, "Error adding extra-certs certificate"); + } + BIO_free (bio); + } + /* Require peer certificate verification */ #if P2MP_SERVER if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) diff --git a/ssl.h b/ssl.h index fe494b1..1b23d7d 100644 --- a/ssl.h +++ b/ssl.h @@ -466,6 +466,7 @@ struct tls_options int ns_cert_type; unsigned remote_cert_ku[MAX_PARMS]; const char *remote_cert_eku; + uint8_t *verify_hash; /* allow openvpn config info to be passed over control channel */ diff --git a/version.m4 b/version.m4 index 85cd043..3642b71 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3u]) +define(PRODUCT_VERSION,[2.1.3v]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3 From e4359af463463097dd80e679836905bcd8ad7a13 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Mon, 25 Apr 2011 06:21:57 +0000 Subject: Fixed compile issues on Windows. Version 2.1.3w git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7219 e7ae566f-a301-0410-adde-c780ea21d3b5 --- init.c | 2 +- options.c | 2 +- options.h | 2 +- version.m4 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/init.c b/init.c index b1f65a9..e5ca358 100644 --- a/init.c +++ b/init.c @@ -2056,6 +2056,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.verify_command = options->tls_verify; to.verify_x509name = options->tls_remote; to.crl_file = options->crl_file; + to.ssl_flags = options->ssl_flags; to.ns_cert_type = options->ns_cert_type; memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku)); to.remote_cert_eku = options->remote_cert_eku; @@ -2076,7 +2077,6 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.auth_user_pass_verify_script = options->auth_user_pass_verify_script; to.auth_user_pass_verify_script_via_file = options->auth_user_pass_verify_script_via_file; to.tmp_dir = options->tmp_dir; - to.ssl_flags = options->ssl_flags; if (options->ccd_exclusive) to.client_config_dir_exclusive = options->client_config_dir; #endif diff --git a/options.c b/options.c index 1cfccd3..df7546c 100644 --- a/options.c +++ b/options.c @@ -1055,7 +1055,6 @@ show_p2mp_parms (const struct options *o) SHOW_INT (max_routes_per_client); SHOW_STR (auth_user_pass_verify_script); SHOW_BOOL (auth_user_pass_verify_script_via_file); - SHOW_INT (ssl_flags); #if PORT_SHARE SHOW_STR (port_share_host); SHOW_INT (port_share_port); @@ -1405,6 +1404,7 @@ show_settings (const struct options *o) SHOW_INT (remote_cert_ku[i]); } SHOW_STR (remote_cert_eku); + SHOW_INT (ssl_flags); SHOW_INT (tls_timeout); diff --git a/options.h b/options.h index f0baabe..91ec6dc 100644 --- a/options.h +++ b/options.h @@ -426,7 +426,6 @@ struct options const char *auth_user_pass_verify_script; bool auth_user_pass_verify_script_via_file; - unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */ #if PORT_SHARE char *port_share_host; int port_share_port; @@ -498,6 +497,7 @@ struct options unsigned remote_cert_ku[MAX_PARMS]; const char *remote_cert_eku; uint8_t *verify_hash; + unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */ #ifdef ENABLE_PKCS11 const char *pkcs11_providers[MAX_PARMS]; diff --git a/version.m4 b/version.m4 index 3642b71..77e4950 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.3v]) +define(PRODUCT_VERSION,[2.1.3w]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3