From patchwork Wed Jul 4 07:53:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steffan Karger X-Patchwork-Id: 400 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director7.mail.ord1d.rsapps.net ([172.27.255.53]) by backend30.mail.ord1d.rsapps.net (Dovecot) with LMTP id 0wrMEhYKPVvCIQAAIUCqbw for ; Wed, 04 Jul 2018 13:55:34 -0400 Received: from proxy10.mail.iad3a.rsapps.net ([172.27.255.53]) by director7.mail.ord1d.rsapps.net (Dovecot) with LMTP id oceYAhYKPVtlaQAAovjBpQ ; Wed, 04 Jul 2018 13:55:34 -0400 Received: from smtp40.gate.iad3a ([172.27.255.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy10.mail.iad3a.rsapps.net with LMTP id 8Eo0CRYKPVuJKQAAnQ/bqA ; Wed, 04 Jul 2018 13:55:34 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp40.gate.iad3a.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dkim=fail (signature verification failed) header.d=karger-me.20150623.gappssmtp.com; dmarc=none (p=nil; dis=none) header.from=karger.me X-Suspicious-Flag: YES X-Classification-ID: 724008f0-7fb3-11e8-bb4b-5254003a14f9-1-1 Received: from [216.105.38.7] ([216.105.38.7:20770] helo=lists.sourceforge.net) by smtp40.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 37/9B-23169-51A0D3B5; Wed, 04 Jul 2018 13:55:33 -0400 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1falzL-0001Pb-Lz; Wed, 04 Jul 2018 17:54:47 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1falzG-0001PH-S3 for openvpn-devel@lists.sourceforge.net; Wed, 04 Jul 2018 17:54:42 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=tRBxEsqAf8VJXH7g6B3ZWfep007e/7QUYFvKvmttdLg=; b=C9wiwVdOngvhHhJXL9AwIEXEt8 TIZNvRtcNBMHZaRD9uiviJBbgTrtuHvspINPX5Ar6joD8nt69ry/06EDkKoI9tw1Km678KQxyGdLO ediOB56JDhSCLWSETtsy8ug7lmVI7JT5JWTcyXVGvEaXceaOJw1zsXC0gD1J0rlUQr8Y=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To :MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=tRBxEsqAf8VJXH7g6B3ZWfep007e/7QUYFvKvmttdLg=; b=HOLjmPjnGfPeRgrYrhmJex28Zw 3nqnIBZij+wr4DhYX6XvYhVoAoISK5p53vUFTLG/jIR6uKhay+9XyzDhxd2Lzw5v+W5xLTflno/nz 0YyUWUNOpPYP2PKqXDK747u4F5rkSKfiVrOxxIkhHF27VP8v7jREzg+NG8SHfDI/Ypg0=; Received: from mail-ed1-f51.google.com ([209.85.208.51]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.90_1) id 1falzD-00HLKe-Jn for openvpn-devel@lists.sourceforge.net; Wed, 04 Jul 2018 17:54:42 +0000 Received: by mail-ed1-f51.google.com with SMTP id v22-v6so4572224edq.4 for ; Wed, 04 Jul 2018 10:54:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=karger-me.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tRBxEsqAf8VJXH7g6B3ZWfep007e/7QUYFvKvmttdLg=; b=nJ6ibNLWnw2yKnEc4JUv3CGocxBlqiNCSZhtyp1CyGGrO2OUW2hVwHDBOPQNS8QMNu gWAQdvcqExCpkljmvFZ1hKhLJsbss28TXhJm0ezCR0vLNoQ3wX+a7QfnHbAsbcrMmPWG PkILSORGG+7Dx5aTXVgCvp4dcZqUtfU+gW7laTWhi07Wbt3K9e4xTSqrJ+45aH6n389p tfelODQx5yNhrZw++b65IsGOLvMp5Yt0rjm+A3+yuCPSmSEIozOxJAeLHG4VP602z4zv uzJSv33ayZeDCYpRyW0DSP0NUn8zsPQ6wrLPZFTYX6H+GUZ3NoiaSIKLfj0gC+fVvZji NS7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=tRBxEsqAf8VJXH7g6B3ZWfep007e/7QUYFvKvmttdLg=; b=uXkllyUI8cAYLF6KWWQia193DxFkwW2u45JbCVYml6+uQHTGYtjPXS1Rl2eWDKEtFf J6XACS0tyJkXdVhb1x+N+8UB5IlQcIKDo2hdfCrtOzFw1S06N5JbxjdMv2mC2WScZNCc VkPi2oyskUfZoSyKe8hTfNzPqEfYYqboS0jLWLjZEbmCLeC0TIm+UBKdsODc2EqY0DEF Sv8fu+zk2nn36pvqNo2zzVYs8BY3n0AGrQorIZU14t0CbrDArx48FcavxCwXtGDcvfmz bysOaU7tv+mP+7W/MSpfQ/oCFgD2o9k93mPFlX8wb8Nr7j+tRu0dRlxmVIqxrcIhmurD JqwQ== X-Gm-Message-State: APt69E0NJW5gTBsIDXPZ42HqDKlsThbxwxXllfYHif5PfLTdgnKyq/kN JUkY6bkKcZDdcwW/p+DAC796nUnt+Uw= X-Google-Smtp-Source: AAOMgpeuESev9LM8JGie4/rParosvJgo78EC3I+koSxeE49ODv3JLorPgLzIWUphlAWBhL3XjvEiQQ== X-Received: by 2002:a50:f577:: with SMTP id w52-v6mr3818522edm.230.1530726872399; Wed, 04 Jul 2018 10:54:32 -0700 (PDT) Received: from vesta.fritz.box ([2001:985:e54:1:f598:331e:3cdf:2649]) by smtp.gmail.com with ESMTPSA id o2-v6sm1948961edd.84.2018.07.04.10.54.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 04 Jul 2018 10:54:31 -0700 (PDT) From: Steffan Karger To: openvpn-devel@lists.sourceforge.net Date: Wed, 4 Jul 2018 19:53:56 +0200 Message-Id: <20180704175404.22371-1-steffan@karger.me> X-Mailer: git-send-email 2.17.1 In-Reply-To: <1512734870-17133-1-git-send-email-steffan.karger@fox-it.com> References: <1512734870-17133-1-git-send-email-steffan.karger@fox-it.com> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [209.85.208.51 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.208.51 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.0 T_DKIMWL_WL_MED DKIMwl.org - Whitelisted Medium sender X-Headers-End: 1falzD-00HLKe-Jn Subject: [Openvpn-devel] [PATCH v2 1/9] Move file-related functions from misc.c to platform.c X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Steffan Karger To avoid having to include misc.c - which is a dependency mess - in the tls-crypt unit tests, move file-handing related functions to platform.c (which is where other file-related functions already reside). Note that platform_create_temp_file() needs random. To avoid including misc.c in other tests that use platform.c, add a mock get_random(). (Almost every test includes platform.c, because buffer.c depends on it. That smells like it needs cleanup too, but not in this patch set.) Signed-off-by: Steffan Karger Acked-by: Gert Doering --- src/openvpn/init.c | 2 +- src/openvpn/misc.c | 148 --------------------- src/openvpn/misc.h | 12 -- src/openvpn/multi.c | 25 ++-- src/openvpn/pf.c | 4 +- src/openvpn/platform.c | 148 +++++++++++++++++++++ src/openvpn/platform.h | 18 +++ src/openvpn/plugin.c | 6 +- src/openvpn/ssl_verify.c | 12 +- tests/unit_tests/openvpn/Makefile.am | 4 + tests/unit_tests/openvpn/mock_get_random.c | 36 +++++ 11 files changed, 233 insertions(+), 182 deletions(-) create mode 100644 tests/unit_tests/openvpn/mock_get_random.c diff --git a/src/openvpn/init.c b/src/openvpn/init.c index b748357d..f6c8f08e 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -807,7 +807,7 @@ init_static(void) #ifdef STATUS_PRINTF_TEST { struct gc_arena gc = gc_new(); - const char *tmp_file = create_temp_file("/tmp", "foo", &gc); + const char *tmp_file = platform_create_temp_file("/tmp", "foo", &gc); struct status_output *so = status_open(tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); status_printf(so, "%s", "foo"); status_printf(so, "%s", "bar"); diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index fc68027f..85cdc95d 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -313,87 +313,6 @@ openvpn_popen(const struct argv *a, const struct env_set *es) return ret; } - -/* return true if filename can be opened for read */ -bool -test_file(const char *filename) -{ - bool ret = false; - if (filename) - { - FILE *fp = platform_fopen(filename, "r"); - if (fp) - { - fclose(fp); - ret = true; - } - else - { - if (openvpn_errno() == EACCES) - { - msg( M_WARN | M_ERRNO, "Could not access file '%s'", filename); - } - } - } - - dmsg(D_TEST_FILE, "TEST FILE '%s' [%d]", - filename ? filename : "UNDEF", - ret); - - return ret; -} - -/* create a temporary filename in directory */ -const char * -create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc) -{ - int fd; - const char *retfname = NULL; - unsigned int attempts = 0; - char fname[256] = { 0 }; - const char *fname_fmt = PACKAGE "_%.*s_%08lx%08lx.tmp"; - const int max_prefix_len = sizeof(fname) - (sizeof(PACKAGE) + 7 + (2 * 8)); - - while (attempts < 6) - { - ++attempts; - - if (!openvpn_snprintf(fname, sizeof(fname), fname_fmt, max_prefix_len, - prefix, (unsigned long) get_random(), - (unsigned long) get_random())) - { - msg(M_WARN, "ERROR: temporary filename too long"); - return NULL; - } - - retfname = gen_path(directory, fname, gc); - if (!retfname) - { - msg(M_WARN, "Failed to create temporary filename and path"); - return NULL; - } - - /* Atomically create the file. Errors out if the file already - * exists. */ - fd = platform_open(retfname, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); - if (fd != -1) - { - close(fd); - return retfname; - } - else if (fd == -1 && errno != EEXIST) - { - /* Something else went wrong, no need to retry. */ - msg(M_WARN | M_ERRNO, "Could not create temporary file '%s'", - retfname); - return NULL; - } - } - - msg(M_WARN, "Failed to create temporary file after %i attempts", attempts); - return NULL; -} - /* * Prepend a random string to hostname to prevent DNS caching. * For example, foo.bar.gov would be modified to .foo.bar.gov. @@ -415,73 +334,6 @@ hostname_randomize(const char *hostname, struct gc_arena *gc) #undef n_rnd_bytes } -/* - * Put a directory and filename together. - */ -const char * -gen_path(const char *directory, const char *filename, struct gc_arena *gc) -{ -#ifdef _WIN32 - const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON - |CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK; -#else - const int CC_PATH_RESERVED = CC_SLASH; -#endif - - if (!gc) - { - return NULL; /* Would leak memory otherwise */ - } - - const char *safe_filename = string_mod_const(filename, CC_PRINT, CC_PATH_RESERVED, '_', gc); - - if (safe_filename - && strcmp(safe_filename, ".") - && strcmp(safe_filename, "..") -#ifdef _WIN32 - && win_safe_filename(safe_filename) -#endif - ) - { - const size_t outsize = strlen(safe_filename) + (directory ? strlen(directory) : 0) + 16; - struct buffer out = alloc_buf_gc(outsize, gc); - char dirsep[2]; - - dirsep[0] = OS_SPECIFIC_DIRSEP; - dirsep[1] = '\0'; - - if (directory) - { - buf_printf(&out, "%s%s", directory, dirsep); - } - buf_printf(&out, "%s", safe_filename); - - return BSTR(&out); - } - else - { - return NULL; - } -} - -bool -absolute_pathname(const char *pathname) -{ - if (pathname) - { - const int c = pathname[0]; -#ifdef _WIN32 - return c == '\\' || (isalpha(c) && pathname[1] == ':' && pathname[2] == '\\'); -#else - return c == '/'; -#endif - } - else - { - return false; - } -} - /* * Get and store a username/password */ diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 5680c274..c23d4cd1 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -79,18 +79,6 @@ const char **make_extended_arg_array(char **p, struct gc_arena *gc); /* an analogue to the random() function, but use OpenSSL functions if available */ long int get_random(void); -/* return true if filename can be opened for read */ -bool test_file(const char *filename); - -/* create a temporary file in directory, returns the filename of the created file */ -const char *create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc); - -/* put a directory and filename together */ -const char *gen_path(const char *directory, const char *filename, struct gc_arena *gc); - -/* return true if pathname is absolute */ -bool absolute_pathname(const char *pathname); - /* prepend a random prefix to hostname */ const char *hostname_randomize(const char *hostname, struct gc_arena *gc); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 3da8c110..2944eef2 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1642,7 +1642,7 @@ multi_client_connect_post(struct multi_context *m, unsigned int *option_types_found) { /* Did script generate a dynamic config file? */ - if (test_file(dc_file)) + if (platform_test_file(dc_file)) { options_server_import(&mi->context.options, dc_file, @@ -1829,12 +1829,13 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi) { const char *ccd_file; - ccd_file = gen_path(mi->context.options.client_config_dir, - tls_common_name(mi->context.c2.tls_multi, false), - &gc); + ccd_file = platform_gen_path(mi->context.options.client_config_dir, + tls_common_name(mi->context.c2.tls_multi, + false), + &gc); /* try common-name file */ - if (test_file(ccd_file)) + if (platform_test_file(ccd_file)) { options_server_import(&mi->context.options, ccd_file, @@ -1845,11 +1846,11 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi) } else /* try default file */ { - ccd_file = gen_path(mi->context.options.client_config_dir, - CCD_DEFAULT, - &gc); + ccd_file = platform_gen_path(mi->context.options.client_config_dir, + CCD_DEFAULT, + &gc); - if (test_file(ccd_file)) + if (platform_test_file(ccd_file)) { options_server_import(&mi->context.options, ccd_file, @@ -1879,7 +1880,8 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi) if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) { struct argv argv = argv_new(); - const char *dc_file = create_temp_file(mi->context.options.tmp_dir, "cc", &gc); + const char *dc_file = platform_create_temp_file(mi->context.options.tmp_dir, + "cc", &gc); if (!dc_file) { @@ -1941,7 +1943,8 @@ script_depr_failed: setenv_str(mi->context.c2.es, "script_type", "client-connect"); - dc_file = create_temp_file(mi->context.options.tmp_dir, "cc", &gc); + dc_file = platform_create_temp_file(mi->context.options.tmp_dir, + "cc", &gc); if (!dc_file) { cc_succeeded = false; diff --git a/src/openvpn/pf.c b/src/openvpn/pf.c index cb22a1cb..d4e405a8 100644 --- a/src/openvpn/pf.c +++ b/src/openvpn/pf.c @@ -621,8 +621,8 @@ pf_init_context(struct context *c) #ifdef PLUGIN_PF if (plugin_defined(c->plugins, OPENVPN_PLUGIN_ENABLE_PF)) { - c->c2.pf.filename = create_temp_file(c->options.tmp_dir, "pf", - &c->c2.gc); + c->c2.pf.filename = platform_create_temp_file(c->options.tmp_dir, "pf", + &c->c2.gc); if (c->c2.pf.filename) { setenv_str(c->c2.es, "pf_file", c->c2.pf.filename); diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c index fbffd0f0..5ecccf1c 100644 --- a/src/openvpn/platform.c +++ b/src/openvpn/platform.c @@ -31,6 +31,7 @@ #include "buffer.h" #include "error.h" +#include "misc.h" #include "win32.h" #include "memdbg.h" @@ -335,3 +336,150 @@ platform_stat(const char *path, platform_stat_t *buf) #endif } +/* create a temporary filename in directory */ +const char * +platform_create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc) +{ + int fd; + const char *retfname = NULL; + unsigned int attempts = 0; + char fname[256] = { 0 }; + const char *fname_fmt = PACKAGE "_%.*s_%08lx%08lx.tmp"; + const int max_prefix_len = sizeof(fname) - (sizeof(PACKAGE) + 7 + (2 * 8)); + + while (attempts < 6) + { + ++attempts; + + if (!openvpn_snprintf(fname, sizeof(fname), fname_fmt, max_prefix_len, + prefix, (unsigned long) get_random(), + (unsigned long) get_random())) + { + msg(M_WARN, "ERROR: temporary filename too long"); + return NULL; + } + + retfname = platform_gen_path(directory, fname, gc); + if (!retfname) + { + msg(M_WARN, "Failed to create temporary filename and path"); + return NULL; + } + + /* Atomically create the file. Errors out if the file already + * exists. */ + fd = platform_open(retfname, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); + if (fd != -1) + { + close(fd); + return retfname; + } + else if (fd == -1 && errno != EEXIST) + { + /* Something else went wrong, no need to retry. */ + msg(M_WARN | M_ERRNO, "Could not create temporary file '%s'", + retfname); + return NULL; + } + } + + msg(M_WARN, "Failed to create temporary file after %i attempts", attempts); + return NULL; +} + +/* + * Put a directory and filename together. + */ +const char * +platform_gen_path(const char *directory, const char *filename, + struct gc_arena *gc) +{ +#ifdef _WIN32 + const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON + |CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK; +#else + const int CC_PATH_RESERVED = CC_SLASH; +#endif + + if (!gc) + { + return NULL; /* Would leak memory otherwise */ + } + + const char *safe_filename = string_mod_const(filename, CC_PRINT, CC_PATH_RESERVED, '_', gc); + + if (safe_filename + && strcmp(safe_filename, ".") + && strcmp(safe_filename, "..") +#ifdef _WIN32 + && win_safe_filename(safe_filename) +#endif + ) + { + const size_t outsize = strlen(safe_filename) + (directory ? strlen(directory) : 0) + 16; + struct buffer out = alloc_buf_gc(outsize, gc); + char dirsep[2]; + + dirsep[0] = OS_SPECIFIC_DIRSEP; + dirsep[1] = '\0'; + + if (directory) + { + buf_printf(&out, "%s%s", directory, dirsep); + } + buf_printf(&out, "%s", safe_filename); + + return BSTR(&out); + } + else + { + return NULL; + } +} + +bool +platform_absolute_pathname(const char *pathname) +{ + if (pathname) + { + const int c = pathname[0]; +#ifdef _WIN32 + return c == '\\' || (isalpha(c) && pathname[1] == ':' && pathname[2] == '\\'); +#else + return c == '/'; +#endif + } + else + { + return false; + } +} + +/* return true if filename can be opened for read */ +bool +platform_test_file(const char *filename) +{ + bool ret = false; + if (filename) + { + FILE *fp = platform_fopen(filename, "r"); + if (fp) + { + fclose(fp); + ret = true; + } + else + { + if (openvpn_errno() == EACCES) + { + msg( M_WARN | M_ERRNO, "Could not access file '%s'", filename); + } + } + } + + dmsg(D_TEST_FILE, "TEST FILE '%s' [%d]", + filename ? filename : "UNDEF", + ret); + + return ret; +} diff --git a/src/openvpn/platform.h b/src/openvpn/platform.h index 288937df..091fc9c4 100644 --- a/src/openvpn/platform.h +++ b/src/openvpn/platform.h @@ -49,6 +49,7 @@ #endif #include "basic.h" +#include "buffer.h" /* Get/Set UID of process */ @@ -143,4 +144,21 @@ typedef struct stat platform_stat_t; #endif int platform_stat(const char *path, platform_stat_t *buf); +/** + * Create a temporary file in directory, returns the filename of the created + * file. + */ +const char *platform_create_temp_file(const char *directory, const char *prefix, + struct gc_arena *gc); + +/** Put a directory and filename together. */ +const char *platform_gen_path(const char *directory, const char *filename, + struct gc_arena *gc); + +/** Return true if pathname is absolute. */ +bool platform_absolute_pathname(const char *pathname); + +/** Return true if filename can be opened for read. */ +bool platform_test_file(const char *filename); + #endif /* ifndef PLATFORM_H */ diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index 0f091ef5..3e7d2b2a 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -249,7 +249,7 @@ plugin_init_item(struct plugin *p, const struct plugin_option *o) * was parsed. * */ - if (!absolute_pathname(p->so_pathname) + if (!platform_absolute_pathname(p->so_pathname) && p->so_pathname[0] != '.') { char full[PATH_MAX]; @@ -259,7 +259,7 @@ plugin_init_item(struct plugin *p, const struct plugin_option *o) } else { - rel = !absolute_pathname(p->so_pathname); + rel = !platform_absolute_pathname(p->so_pathname); p->handle = dlopen(p->so_pathname, RTLD_NOW); } if (!p->handle) @@ -271,7 +271,7 @@ plugin_init_item(struct plugin *p, const struct plugin_option *o) #else /* ifndef _WIN32 */ - rel = !absolute_pathname(p->so_pathname); + rel = !platform_absolute_pathname(p->so_pathname); p->module = LoadLibraryW(wide_string(p->so_pathname, &gc)); if (!p->module) { diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 25395b27..a3699252 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -547,7 +547,7 @@ verify_cert_export_cert(openvpn_x509_cert_t *peercert, const char *tmp_dir, stru /* create tmp file to store peer cert */ if (!tmp_dir - || !(peercert_filename = create_temp_file(tmp_dir, "pcf", gc))) + || !(peercert_filename = platform_create_temp_file(tmp_dir, "pcf", gc))) { msg(M_NONFATAL, "Failed to create peer cert file"); return NULL; @@ -890,7 +890,7 @@ key_state_gen_auth_control_file(struct key_state *ks, const struct tls_options * struct gc_arena gc = gc_new(); key_state_rm_auth_control_file(ks); - const char *acf = create_temp_file(opt->tmp_dir, "acf", &gc); + const char *acf = platform_create_temp_file(opt->tmp_dir, "acf", &gc); if (acf) { ks->auth_control_file = string_alloc(acf, NULL); @@ -1103,7 +1103,8 @@ verify_user_pass_script(struct tls_session *session, const struct user_pass *up) { struct status_output *so; - tmp_file = create_temp_file(session->opt->tmp_dir, "up", &gc); + tmp_file = platform_create_temp_file(session->opt->tmp_dir, "up", + &gc); if (tmp_file) { so = status_open(tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); @@ -1513,8 +1514,9 @@ verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session) struct gc_arena gc = gc_new(); const char *cn = session->common_name; - const char *path = gen_path(session->opt->client_config_dir_exclusive, cn, &gc); - if (!cn || !strcmp(cn, CCD_DEFAULT) || !test_file(path)) + const char *path = platform_gen_path(session->opt->client_config_dir_exclusive, + cn, &gc); + if (!cn || !strcmp(cn, CCD_DEFAULT) || !platform_test_file(path)) { ks->authenticated = false; wipe_auth_token(multi); diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index 23d758b7..db4d46e1 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -19,6 +19,7 @@ argv_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) \ argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line \ $(OPTIONAL_CRYPTO_LIBS) argv_testdriver_SOURCES = test_argv.c mock_msg.c \ + mock_get_random.c \ $(openvpn_srcdir)/platform.c \ $(openvpn_srcdir)/buffer.c \ $(openvpn_srcdir)/argv.c @@ -26,6 +27,7 @@ argv_testdriver_SOURCES = test_argv.c mock_msg.c \ buffer_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) buffer_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line buffer_testdriver_SOURCES = test_buffer.c mock_msg.c \ + mock_get_random.c \ $(openvpn_srcdir)/buffer.c \ $(openvpn_srcdir)/platform.c @@ -35,6 +37,7 @@ packet_id_testdriver_CFLAGS = @TEST_CFLAGS@ \ packet_id_testdriver_LDFLAGS = @TEST_LDFLAGS@ \ $(OPTIONAL_CRYPTO_LIBS) packet_id_testdriver_SOURCES = test_packet_id.c mock_msg.c \ + mock_get_random.c \ $(openvpn_srcdir)/buffer.c \ $(openvpn_srcdir)/otime.c \ $(openvpn_srcdir)/packet_id.c \ @@ -46,6 +49,7 @@ tls_crypt_testdriver_CFLAGS = @TEST_CFLAGS@ \ tls_crypt_testdriver_LDFLAGS = @TEST_LDFLAGS@ \ $(OPTIONAL_CRYPTO_LIBS) tls_crypt_testdriver_SOURCES = test_tls_crypt.c mock_msg.c \ + $(openvpn_srcdir)/base64.c \ $(openvpn_srcdir)/buffer.c \ $(openvpn_srcdir)/crypto.c \ $(openvpn_srcdir)/crypto_mbedtls.c \ diff --git a/tests/unit_tests/openvpn/mock_get_random.c b/tests/unit_tests/openvpn/mock_get_random.c new file mode 100644 index 00000000..da92a9bb --- /dev/null +++ b/tests/unit_tests/openvpn/mock_get_random.c @@ -0,0 +1,36 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2017 Fox Crypto B.V. + * + * 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; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include + +unsigned long +get_random(void) +{ + /* rand() is not very random, but it's C99 and this is just for testing */ + return rand(); +}