git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: "Carlo Marcelo Arenas Belón" <carenas@gmail.com>
Cc: git@vger.kernel.org, dirk@ed4u.de, sunshine@sunshineco.com,
	peff@peff.net, jrnieder@gmail.com, Johannes.Schindelin@gmx.de
Subject: Re: [PATCH v9] credential-store: warn instead of fatal for bogus lines from store
Date: Thu, 30 Apr 2020 13:21:06 -0700	[thread overview]
Message-ID: <xmqq1ro4sp1p.fsf@gitster.c.googlers.com> (raw)
In-Reply-To: <20200430160642.90096-1-carenas@gmail.com> ("Carlo Marcelo Arenas Belón"'s message of "Thu, 30 Apr 2020 09:06:42 -0700")

Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:

> With the added checks for invalid URLs in credentials, any locally
> modified store files which might have empty lines or even comments
> were reported[1] failing to parse as valid credentials.
>
> Instead of doing a hard check for credentials, do a soft one and
> therefore avoid the reported fatal error.
>
> Warn the user indicating the filename and line number so any invalid
> entries could be corrected but continue parsing until a match is
> found or all valid credentials are processed.
>
> Make sure that the credential that we will use to match is complete by
> confirming it has all fields set as expected by the updated rules.
>
> [1] https://stackoverflow.com/a/61420852/5005936
>
> Reported-by: Dirk <dirk@ed4u.de>
> Helped-by: Eric Sunshine <sunshine@sunshineco.com>
> Based-on-patch-by: Jonathan Nieder <jrnieder@gmail.com>
> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
> ---

Looks good.

> diff --git a/credential-store.c b/credential-store.c
> index c010497cb2..b1f5b2dea6 100644
> --- a/credential-store.c
> +++ b/credential-store.c
> @@ -4,10 +4,20 @@
>  #include "string-list.h"
>  #include "parse-options.h"
>  
> +#define PARSE_VERBOSE 0x01
> +
>  static struct lock_file credential_lock;
>  
> +static int valid_credential(struct credential *entry)
> +{
> +	return (entry->username && entry->password &&
> +		entry->protocol && *entry->protocol &&
> +		((entry->host && *entry->host) || entry->path));
> +}

OK.

>  static int parse_credential_file(const char *fn,
>  				  struct credential *c,
> +				  int flags,
>  				  void (*match_cb)(struct credential *),
>  				  void (*other_cb)(struct strbuf *))
>  {
> @@ -15,6 +25,7 @@ static int parse_credential_file(const char *fn,
>  	struct strbuf line = STRBUF_INIT;
>  	struct credential entry = CREDENTIAL_INIT;
>  	int found_credential = 0;
> +	int lineno = 0;
>  
>  	fh = fopen(fn, "r");
>  	if (!fh) {
> @@ -23,17 +34,24 @@ static int parse_credential_file(const char *fn,
>  		return found_credential;
>  	}
>  
> -	while (strbuf_getline_lf(&line, fh) != EOF) {
> -		credential_from_url(&entry, line.buf);
> -		if (entry.username && entry.password &&
> -		    credential_match(c, &entry)) {
> +	while (strbuf_getline(&line, fh) != EOF) {

Hmph, I probably have missed some discussion that happened in the
last few days, but from the use of _lf() in the original, I sense
that it is very much deliberate that the file format is designed to
be LF delimited records, *not* a text file in which each line is
terminated with some end-of-line marker that is platform dependent.
IOW, an explicit use of _lf() shouts, at least to me, that we want a
sequence of LF terminated records even on Windows and Macs.

So, I am not sure why this change is desirable.

> +		lineno++;
> +
> +		if (credential_from_url_gently(&entry, line.buf, 1) ||
> +			!valid_credential(&entry)) {

OK, so we read a line, fed it to the parser, and if we had trouble
parsing or the line did not have enough credential material, we
discard and warn (when told to).

> +			if (flags & PARSE_VERBOSE)
> +				warning(_("%s:%d: ignoring invalid credential"),
> +					fn, lineno);
> +		} else if (credential_match(c, &entry)) {
>  			found_credential = 1;
>  			if (match_cb) {
>  				match_cb(&entry);
>  				break;
>  			}
> +			continue;

And if the credential material on a good line matches, we remember
we saw a match.  If there is match callback, we call it and leave
the loop to return from the function.  Otherwise we go to the next
line.
>  		}
> +
> +		if (other_cb)
>  			other_cb(&line);

A malformed/underspecified line and an unmatched line is fed to the
other callback.

>  	}
>  
> @@ -62,7 +80,7 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
>  		die_errno("unable to get credential storage lock");
>  	if (extra)
>  		print_line(extra);
> -	parse_credential_file(fn, c, NULL, print_line);
> +	parse_credential_file(fn, c, 0, NULL, print_line);

This helper function is called from two places.

 - In store_credential_file, we write the credential we were asked
   to store to a strbuf, and then call this function.  The function
   first writes that new credential and then calls the parse helper
   without PARSE_VERBOSE.  We do not give any match callback, and
   other callback is to just print the line read from the credential
   file.  So, the final output would be the new credential, followed
   by the current contents of the credential file except for the
   records that match the one we are storing.  We do this without
   warning about malformed entries at all.

 - In remove_credential, we go over multiple files and copy the
   lines in each of them, except the ones that match the credential
   we are given.  We also do this without warning about malformed
   entries at all.

>  	if (commit_lock_file(&credential_lock) < 0)
>  		die_errno("unable to write credential store");
>  }
> @@ -139,7 +157,8 @@ static void lookup_credential(const struct string_list *fns, struct credential *
>  	struct string_list_item *fn;
>  
>  	for_each_string_list_item(fn, fns)
> -		if (parse_credential_file(fn->string, c, print_entry, NULL))
> +		if (parse_credential_file(fn->string, c, PARSE_VERBOSE,
> +						 print_entry, NULL))
>  			return; /* Found credential */
>  }

This is triggered by the "get" operation.  We read until we hit the
entry we are looking for, at that point the match-callback will
print out "username=... / password=..." lines and we ignore the
remainder of the file.  While we look for the first matching
credential, we do warn about malformed or underspecified lines that
we are ignoring, but because we leave the loop once a matching line
is found, bad lines that come after it won't be even looked at to be
warned.

Validating and warning about bad entries is *not* the main purpose
of the "credential-store" program, so I fully agree with the design
of the "get" part.  I am not so sure about the other two operations
(i.e. "store" and "erase") that do scan all the entries and has
chance to warn about bad ones, though (note: I am not saying that we
should parse verbosely---it is just that I do not know why you chose
not to and I am not convinced that it is a good idea not to warn).

The tests looked good.

Thanks.


  reply	other threads:[~2020-04-30 20:21 UTC|newest]

Thread overview: 79+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-26 23:47 [PATCH] git-credential-store: skip empty lines and comments from store Carlo Marcelo Arenas Belón
2020-04-27  0:19 ` Eric Sunshine
2020-04-27  0:46   ` Carlo Marcelo Arenas Belón
2020-04-27  8:42 ` [PATCH v2] " Carlo Marcelo Arenas Belón
2020-04-27 11:52   ` Jeff King
2020-04-27 12:25     ` Carlo Marcelo Arenas Belón
2020-04-27 14:43       ` Eric Sunshine
2020-04-27 17:47     ` Junio C Hamano
2020-04-27 19:09       ` Jeff King
2020-04-27 12:59   ` [PATCH v3] " Carlo Marcelo Arenas Belón
2020-04-27 13:48     ` Philip Oakley
2020-04-28  1:49       ` Carlo Marcelo Arenas Belón
2020-04-29 10:09         ` Philip Oakley
2020-04-27 15:39     ` Dirk
2020-04-27 18:09     ` Junio C Hamano
2020-04-27 19:18       ` Jeff King
2020-04-27 20:43         ` Junio C Hamano
2020-04-27 21:10           ` Jeff King
2020-04-28  1:37             ` Carlo Marcelo Arenas Belón
2020-04-27 23:49           ` Carlo Marcelo Arenas Belón
2020-04-28  5:25           ` Jonathan Nieder
2020-04-28  5:41             ` Jeff King
2020-04-28  7:18               ` Carlo Marcelo Arenas Belón
2020-04-28  8:16                 ` Jeff King
2020-04-28 11:25                   ` Carlo Marcelo Arenas Belón
2020-04-28 10:58             ` Stefan Tauner
2020-04-28 16:03             ` Junio C Hamano
2020-04-28 21:14               ` Carlo Marcelo Arenas Belón
2020-04-28 21:17                 ` Junio C Hamano
2020-04-28 10:48     ` [PATCH v4 0/4] credential-store: prevent fatal errors Carlo Marcelo Arenas Belón
2020-04-28 10:52       ` [PATCH v4 1/4] credential-store: document the file format a bit more Carlo Marcelo Arenas Belón
2020-04-28 10:52         ` [PATCH v4 2/4] git-credential-store: skip empty lines and comments from store Carlo Marcelo Arenas Belón
2020-04-28 16:09           ` Eric Sunshine
2020-04-28 16:42             ` Carlo Marcelo Arenas Belón
2020-04-28 10:52         ` [PATCH v4 3/4] git-credential-store: fix (WIP) Carlo Marcelo Arenas Belón
2020-04-28 16:11           ` Eric Sunshine
2020-04-28 17:14             ` Carlo Marcelo Arenas Belón
2020-04-28 10:52         ` [PATCH v4 4/4] credential-store: make sure there is no regression with missing scheme Carlo Marcelo Arenas Belón
2020-04-28 16:06         ` [PATCH v4 1/4] credential-store: document the file format a bit more Eric Sunshine
2020-04-28 18:18           ` Junio C Hamano
2020-04-28 18:15         ` Junio C Hamano
2020-04-29  0:33       ` [PATCH v5] credential-store: warn instead of fatal for bogus lines from store Carlo Marcelo Arenas Belón
2020-04-29  4:36         ` Junio C Hamano
2020-04-29  7:31           ` Carlo Marcelo Arenas Belón
2020-04-29 16:46             ` Junio C Hamano
2020-04-29 20:35         ` [RFC PATCH v6 0/2] credential-store: prevent fatal errors Carlo Marcelo Arenas Belón
2020-04-29 20:35           ` [RFC PATCH v6 1/2] credential-store: warn instead of fatal for bogus lines from store Carlo Marcelo Arenas Belón
2020-04-29 21:05             ` Junio C Hamano
2020-04-29 21:17               ` Junio C Hamano
2020-04-29 20:35           ` [RFC PATCH v6 2/2] credential-store: warn for any incomplete credentials instead of using Carlo Marcelo Arenas Belón
2020-04-29 21:12             ` Junio C Hamano
2020-04-29 21:49               ` [RFC PATCH v6 2/2] credential-store: warn for any incomplete credentials instead of usingy Carlo Marcelo Arenas Belón
2020-04-29 22:04                 ` Junio C Hamano
2020-04-29 23:23           ` [PATCH v6] credential-store: warn instead of fatal for bogus lines from store Carlo Marcelo Arenas Belón
2020-04-29 23:47             ` Junio C Hamano
2020-04-29 23:57               ` Junio C Hamano
2020-04-30  1:00               ` Carlo Marcelo Arenas Belón
2020-04-30  1:19             ` [PATCH v7] " Carlo Marcelo Arenas Belón
2020-04-30  9:29               ` [PATCH v8] " Carlo Marcelo Arenas Belón
2020-04-30 16:06               ` [PATCH v9] " Carlo Marcelo Arenas Belón
2020-04-30 20:21                 ` Junio C Hamano [this message]
2020-04-30 21:14                   ` Junio C Hamano
2020-05-01  0:30                   ` Carlo Marcelo Arenas Belón
2020-05-01  1:40                     ` Junio C Hamano
2020-05-01  2:24                       ` Carlo Arenas
2020-05-01  5:27                         ` Junio C Hamano
2020-05-01 13:57                           ` Carlo Marcelo Arenas Belón
2020-05-01 18:59                             ` Junio C Hamano
2020-05-01  3:21                 ` [RFC PATCH v10] credential-store: warn/ignore for bogus lines from store file Carlo Marcelo Arenas Belón
2020-05-01  5:18                   ` [RFC PATCH v10 2/1] credential-store: warn also for store and erase Carlo Marcelo Arenas Belón
2020-05-01  5:35                     ` Junio C Hamano
2020-05-02 18:16                 ` [PATCH v10] credential-store: ignore bogus lines from store file Carlo Marcelo Arenas Belón
2020-05-02 20:47                   ` Junio C Hamano
2020-05-02 21:23                     ` Carlo Marcelo Arenas Belón
2020-05-02 21:53                     ` Carlo Marcelo Arenas Belón
2020-05-03  0:44                       ` Junio C Hamano
2020-05-03 10:06                     ` Jeff King
2020-05-02 21:05                   ` Carlo Marcelo Arenas Belón
2020-05-02 22:34                   ` [PATCH v11] " Carlo Marcelo Arenas Belón

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=xmqq1ro4sp1p.fsf@gitster.c.googlers.com \
    --to=gitster@pobox.com \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=carenas@gmail.com \
    --cc=dirk@ed4u.de \
    --cc=git@vger.kernel.org \
    --cc=jrnieder@gmail.com \
    --cc=peff@peff.net \
    --cc=sunshine@sunshineco.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).