Hi,

Thanks a lot for reworking your contribution!

On 12/04/2021 18:45, Max Fillinger wrote:
> When using the chroot option, the init_ssl function can be called before
> entering the chroot or, when OpenVPN receives a SIGHUP, afterwards. This
> commit ensures that OpenVPN tries to open the correct path for the CRL
> file in either situations.
> 
> This commit does not address key and certificate files. For these, the
> --persist-key option should be used.
> 
> Signed-off-by: Max Fillinger <maximilian.fillin...@foxcrypto.com>
> ---
>  src/openvpn/init.c    |  3 ++-
>  src/openvpn/misc.c    | 11 +++++++++++
>  src/openvpn/misc.h    |  7 +++++++
>  src/openvpn/options.c |  8 +-------
>  src/openvpn/ssl.c     | 20 ++++++++++++++++++--
>  src/openvpn/ssl.h     |  2 +-
>  6 files changed, 40 insertions(+), 11 deletions(-)
> 
> diff --git a/src/openvpn/init.c b/src/openvpn/init.c
> index 28d183aa..ba38e548 100644
> --- a/src/openvpn/init.c
> +++ b/src/openvpn/init.c
> @@ -2702,7 +2702,8 @@ do_init_crypto_tls_c1(struct context *c)
>           * Initialize the OpenSSL library's global
>           * SSL context.
>           */
> -        init_ssl(options, &(c->c1.ks.ssl_ctx));
> +        bool in_chroot = (c->c0 != NULL) ? c->c0->uid_gid_chroot_set : false;
> +        init_ssl(options, &(c->c1.ks.ssl_ctx), in_chroot);

Our codestyle (that is not yet 100% consistent all over the place...)
prefers checks for pointers to simply be "if (ptr)" or "if (!ptr)".
Explicit comparison with NULL is not required.

This said, I would simplify these two lines above as:

2706         init_ssl(options, &(c->c1.ks.ssl_ctx),
2707                  c->c0 && c->c0->uid_gid_chroot_set);

(I removed the local variable, but that's more a matter of taste)

>          if (!tls_ctx_initialised(&c->c1.ks.ssl_ctx))
>          {
>              switch (auth_retry_get())
> diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c
> index feaefb3b..a64803a7 100644
> --- a/src/openvpn/misc.c
> +++ b/src/openvpn/misc.c
> @@ -767,3 +767,14 @@ get_num_elements(const char *string, char delimiter)
>  
>      return element_count;
>  }
> +
> +struct buffer
> +prepend_chroot(const char *chroot_dir, const char *path, struct gc_arena *gc)
> +{

maybe we should just call this prepend_dir(dir, path, gc) ?
After all this is just doing a dir + '/' + filename; the fact that the
dir is the chroot-dir is due to the usecase, not about what the function
does.

> +    size_t len = strlen(chroot_dir) + strlen(PATH_SEPARATOR_STR) + 
> strlen(path) + 1;
> +    struct buffer combined_path = alloc_buf_gc(len, gc);
> +    buf_printf(&combined_path, "%s%s%s", chroot_dir, PATH_SEPARATOR_STR, 
> path);
> +    ASSERT(combined_path.len > 0);
> +
> +    return combined_path;
> +}
> diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h
> index 9b018eb5..9f352754 100644
> --- a/src/openvpn/misc.h
> +++ b/src/openvpn/misc.h
> @@ -190,4 +190,11 @@ void output_peer_info_env(struct env_set *es, const char 
> *peer_info);
>  int
>  get_num_elements(const char *string, char delimiter);
>  
> +/**
> + * Prepend the chroot directory to a path. Used when we need to access
> + * a file in the chroot directory before we have chroot-ed.
> + */
> +struct buffer
> +prepend_chroot(const char *chroot_dir, const char *path, struct gc_arena 
> *gc);
> +
>  #endif /* ifndef MISC_H */
> diff --git a/src/openvpn/options.c b/src/openvpn/options.c
> index 9e61b1e0..d6ba2938 100644
> --- a/src/openvpn/options.c
> +++ b/src/openvpn/options.c
> @@ -3317,14 +3317,8 @@ check_file_access_chroot(const char *chroot, const int 
> type, const char *file, c
>      {
>          struct gc_arena gc = gc_new();
>          struct buffer chroot_file;
> -        int len = 0;
> -
> -        /* Build up a new full path including chroot directory */
> -        len = strlen(chroot) + strlen(PATH_SEPARATOR_STR) + strlen(file) + 1;
> -        chroot_file = alloc_buf_gc(len, &gc);
> -        buf_printf(&chroot_file, "%s%s%s", chroot, PATH_SEPARATOR_STR, file);
> -        ASSERT(chroot_file.len > 0);
>  
> +        chroot_file = prepend_chroot(chroot, file, &gc);
>          ret = check_file_access(type, BSTR(&chroot_file), mode, opt);
>          gc_free(&gc);
>      }
> diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
> index d8662d00..8782b140 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -584,7 +584,7 @@ tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const 
> char *crl_file,
>   * All files are in PEM format.
>   */
>  void
> -init_ssl(const struct options *options, struct tls_root_ctx *new_ctx)
> +init_ssl(const struct options *options, struct tls_root_ctx *new_ctx, bool 
> in_chroot)
>  {
>      ASSERT(NULL != new_ctx);
>  
> @@ -702,7 +702,23 @@ init_ssl(const struct options *options, struct 
> tls_root_ctx *new_ctx)
>      /* Read CRL */
>      if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR))
>      {
> -        tls_ctx_reload_crl(new_ctx, options->crl_file, 
> options->crl_file_inline);
> +        /* If we're running with the chroot option, we may run init_ssl() 
> before
> +         * and after chroot-ing. We can use the crl_file path as-is if we're
> +         * not going to chroot, or if we already are inside the chroot.

"if" not going to chroot ?

> +         *
> +         * If we're going to chroot later, we need to prefix the path of the
> +         * chroot directory to crl_file. */

multiline comments should always end with */ on the last line

> +        if (options->chroot_dir == NULL || in_chroot || 
> options->crl_file_inline)
> +        {
> +            tls_ctx_reload_crl(new_ctx, options->crl_file, 
> options->crl_file_inline);
> +        }
> +        else
> +        {
> +            struct gc_arena gc = gc_new();
> +            struct buffer crl_file_buf = prepend_chroot(options->chroot_dir, 
> options->crl_file, &gc);
> +            tls_ctx_reload_crl(new_ctx, BSTR(&crl_file_buf), 
> options->crl_file_inline);
> +            gc_free(&gc);
> +        }

Arne: any opinion on using c->c2.gc here? init_ssl() is invoked once per
instance and re-invoked upon SIGUSR1. I believe it is fine to use the
c2's gc?


Assuming the answer to the above is true, I would suggest the following
simplification (compile tested only!):

 704     if (options->crl_file && !(options->ssl_flags &
SSLF_CRL_VERIFY_DIR))
 705     {
 706         const char *crl_data = options->crl_file;
 707
 708         /* If we're running with the chroot option, we may run
init_ssl() before
 709          * and after chroot-ing. We can use the crl_file path as-is
if we're
 710          * not going to chroot, or if we already are inside the chroot.
 711          *
 712          * If we're going to chroot later, we need to prefix the
path of the
 713          * chroot directory to crl_file.
 714          */
 715         if (!in_chroot && !options->crl_file_inline &&
options->chroot_dir)
 716         {
 717             struct buffer crl_file_buf =
prepend_chroot(options->chroot_dir,
 718
options->crl_file, gc);
 719             crl_data = BSTR(&crl_file_buf);
 720         }
 721
 722         tls_ctx_reload_crl(new_ctx, crl_data,
options->crl_file_inline);
 723     }

what do you think?

>      }
>  
>      /* Once keys and cert are loaded, load ECDH parameters */
> diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h
> index 300a70d3..45ebe720 100644
> --- a/src/openvpn/ssl.h
> +++ b/src/openvpn/ssl.h
> @@ -159,7 +159,7 @@ void free_ssl_lib(void);
>   * Build master SSL context object that serves for the whole of OpenVPN
>   * instantiation
>   */
> -void init_ssl(const struct options *options, struct tls_root_ctx *ctx);
> +void init_ssl(const struct options *options, struct tls_root_ctx *ctx, bool 
> in_chroot);
>  
>  /** @addtogroup control_processor
>   *  @{ */
> 


Regards,

-- 
Antonio Quartulli


_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to