From: Dr. David von Oheimb Date: Fri, 27 Sep 2024 06:24:45 +0000 (+0200) Subject: APPS/storeutl: fix case where uri and outfile are the same X-Git-Tag: openssl-3.5.0-alpha1~1019 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=187952d449e4ec6c4fe71a537fa26005556e461a;p=thirdparty%2Fopenssl.git APPS/storeutl: fix case where uri and outfile are the same Reviewed-by: Viktor Dukhovni Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/25559) --- diff --git a/apps/storeutl.c b/apps/storeutl.c index 249dc75c83a..b131278a859 100644 --- a/apps/storeutl.c +++ b/apps/storeutl.c @@ -18,9 +18,11 @@ static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, int expected, int criterion, OSSL_STORE_SEARCH *search, - int text, int noout, int recursive, int indent, BIO *out, + int text, int noout, int recursive, int indent, const char *outfile, const char *prog, OSSL_LIB_CTX *libctx); +static BIO *out = NULL; + typedef enum OPTION_choice { OPT_COMMON, OPT_ENGINE, OPT_OUT, OPT_PASSIN, @@ -71,7 +73,6 @@ int storeutl_main(int argc, char *argv[]) { int ret = 1, noout = 0, text = 0, recursive = 0; char *outfile = NULL, *passin = NULL, *passinarg = NULL; - BIO *out = NULL; ENGINE *e = NULL; OPTION_CHOICE o; char *prog; @@ -311,13 +312,9 @@ int storeutl_main(int argc, char *argv[]) pw_cb_data.password = passin; pw_cb_data.prompt_info = argv[0]; - out = bio_open_default(outfile, 'w', FORMAT_TEXT); - if (out == NULL) - goto end; - ret = process(argv[0], get_ui_method(), &pw_cb_data, expected, criterion, search, - text, noout, recursive, 0, out, prog, libctx); + text, noout, recursive, 0, outfile, prog, libctx); end: EVP_MD_free(digest); @@ -348,7 +345,7 @@ static int indent_printf(int indent, BIO *bio, const char *format, ...) static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, int expected, int criterion, OSSL_STORE_SEARCH *search, - int text, int noout, int recursive, int indent, BIO *out, + int text, int noout, int recursive, int indent, const char *outfile, const char *prog, OSSL_LIB_CTX *libctx) { OSSL_STORE_CTX *store_ctx = NULL; @@ -427,6 +424,13 @@ static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, indent_printf(indent, bio_out, "%d: %s\n", items, infostr); } + if (out == NULL) { + if ((out = bio_open_default(outfile, 'w', FORMAT_TEXT)) == NULL) { + ret++; + goto end2; + } + } + /* * Unfortunately, PEM_X509_INFO_write_bio() is sorely lacking in * functionality, so we must figure out how exactly to write things @@ -438,7 +442,7 @@ static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata, const char *suburi = OSSL_STORE_INFO_get0_NAME(info); ret += process(suburi, uimeth, uidata, expected, criterion, search, - text, noout, recursive, indent + 2, out, prog, + text, noout, recursive, indent + 2, outfile, prog, libctx); } break; diff --git a/doc/man1/openssl-storeutl.pod.in b/doc/man1/openssl-storeutl.pod.in index bdae5995553..75acb077430 100644 --- a/doc/man1/openssl-storeutl.pod.in +++ b/doc/man1/openssl-storeutl.pod.in @@ -45,8 +45,11 @@ Print out a usage message. =item B<-out> I -specifies the output filename to write to or standard output by -default. +This specifies the output file to write to. +Standard output is used if this option is not present. +The output file can be the same as the input, +which leads to replacing the file contents. +Note that file I/O is not atomic. The output file is truncated and then written. =item B<-noout> diff --git a/test/recipes/90-test_store.t b/test/recipes/90-test_store.t index 7c5624e5a22..f0f9e4d94b1 100644 --- a/test/recipes/90-test_store.t +++ b/test/recipes/90-test_store.t @@ -16,6 +16,8 @@ use OpenSSL::Test::Utils; my $test_name = "test_store"; setup($test_name); +require(srctop_file("test", "recipes", "tconversion.pl")); # for test_file_contains() + my $use_md5 = !disabled("md5"); my $use_des = !(disabled("des") || disabled("legacy")); # also affects 3des and pkcs12 app my $use_dsa = !disabled("dsa"); @@ -106,7 +108,7 @@ push @methods, [ @prov_method ]; push @methods, [qw(-engine loader_attic)] unless disabled('loadereng'); -my $n = 2 + scalar @methods +my $n = 4 + scalar @methods * ( (3 * scalar @noexist_files) + (6 * scalar @src_files) + (2 * scalar @data_files) @@ -172,6 +174,11 @@ indir "store_$$" => sub { my $rehash = init_rehash(); + ok(run(app(["openssl", "storeutl", "-out", "cacert.pem", "cacert.pem"])), + "identical infile and outfile"); + test_file_contains("storeutl output on same input", + "cacert.pem", "Total found: 1"); + foreach my $method (@methods) { my @storeutl = ( qw(openssl storeutl), @$method );