After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 703277 - [review] dcbw/need-secrets: request secrets asynchronously (vpnc)
[review] dcbw/need-secrets: request secrets asynchronously (vpnc)
Status: RESOLVED FIXED
Product: NetworkManager
Classification: Platform
Component: VPN: vpnc
unspecified
Other Linux
: Normal normal
: ---
Assigned To: NetworkManager maintainer(s)
NetworkManager maintainer(s)
: 584690 (view as bug list)
Depends on: 703276
Blocks:
 
 
Reported: 2013-06-28 17:50 UTC by Dan Williams
Modified: 2014-09-29 14:37 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Dan Williams 2013-06-28 17:50:24 UTC
We need patches to vpnc to do this, those are posted here:

http://lists.unix-ag.uni-kl.de/pipermail/vpnc-devel/2013-June/003933.html

Beyond that, parse vpnc output and kick off an async need-secrets request when vpnc asks us for something else.
Comment 1 Dan Winship 2013-07-05 19:20:54 UTC
>    core: add function and testcase to parse vpnc stdout/stderr

utils_handle_output() is a really confusing function... I don't have any specific suggestions though. You should definitely document its calling conventions though, so people hacking on this later don't have to reverse-engineer it.

In test-vpnc-output.c, you should put a "{" after each use of TEST_HEADER and a "}" before each use of TEST_FOOTER, so people's editors will keep the "body" indented the way you have it.



>    core: parse vpnc stdin/stdout and request secrets asynchronously

This adds a hard dependency on new vpnc, but doesn't check for it and will just bomb completely on old vpnc...

>+		status = g_io_channel_read_chars (pipe->channel,
>+				                          buf,

indent


>+	} while (/* status == G_IO_STATUS_AGAIN || */ bytes_read);

Remove the commented-out part, since you definitely don't want that.
Comment 2 Jiri Klimes 2013-07-08 12:28:13 UTC
(In reply to comment #1)
> >    core: add function and testcase to parse vpnc stdout/stderr
> 
> utils_handle_output() is a really confusing function... I don't have any
> specific suggestions though. You should definitely document its calling
> conventions though, so people hacking on this later don't have to
> reverse-engineer it.
> 

Yeah, I guess it's quite tricky to parse the stuff. I didn't spot any issue on reading the code, but I didn't run/test that.
Comment 3 Dan Williams 2013-07-09 15:26:28 UTC
(In reply to comment #1)
> >    core: add function and testcase to parse vpnc stdout/stderr
> 
> utils_handle_output() is a really confusing function... I don't have any
> specific suggestions though. You should definitely document its calling
> conventions though, so people hacking on this later don't have to
> reverse-engineer it.

Ok.

> In test-vpnc-output.c, you should put a "{" after each use of TEST_HEADER and a
> "}" before each use of TEST_FOOTER, so people's editors will keep the "body"
> indented the way you have it.
> 
> 
> 
> >    core: parse vpnc stdin/stdout and request secrets asynchronously
> 
> This adds a hard dependency on new vpnc, but doesn't check for it and will just
> bomb completely on old vpnc...

Yeah, not sure how to do that.  vpnc prints it's version # to stdout, but that's long after we need to know whether to use the old code or the new code.  Upstream suggested using the SVN revision somehow (???) but that's not really workable.  I suppose we could run "vpnc --long-help" and grep for "interactive-stdin", but upstream also asked if there wasn't some way to autodetect that stdin was a tty or whatever.  So some of this is going to be pending on the final format of the upstream patches, but the mechanics of handling stdin won't change.

> >+		status = g_io_channel_read_chars (pipe->channel,
> >+				                          buf,
> 
> indent
> 
> 
> >+	} while (/* status == G_IO_STATUS_AGAIN || */ bytes_read);
> 
> Remove the commented-out part, since you definitely don't want that.
Comment 4 Pavel Simerda 2013-07-11 09:30:34 UTC
Looks good.

In my opinion a drop off is not strictly a programmer error but an external condition. Are the g_return_if_fail() just last resort checks or do you expect them to actually occur? In my opinion an attempt to talk to a disconnected agent is either a programming error that should be fixed (if the caller knows that in time) or it's internally a valid condition that deserves at least one real error message but no [soft] assertions afterwards.
Comment 5 Pavel Simerda 2013-07-11 09:37:17 UTC
(In reply to comment #4)
> Looks good.
> 
> In my opinion a drop off is not strictly a programmer error but an external
> condition. Are the g_return_if_fail() just last resort checks or do you expect
> them to actually occur? In my opinion an attempt to talk to a disconnected
> agent is either a programming error that should be fixed (if the caller knows
> that in time) or it's internally a valid condition that deserves at least one
> real error message but no [soft] assertions afterwards.

Please ignore, wrong bug report.

Btw, dcbw/need-secrets doesn't exist, is it merged already or renamed?
Comment 6 Dan Williams 2013-07-14 15:18:06 UTC
(In reply to comment #5)
> (In reply to comment #4)
> > Looks good.
> > 
> > In my opinion a drop off is not strictly a programmer error but an external
> > condition. Are the g_return_if_fail() just last resort checks or do you expect
> > them to actually occur? In my opinion an attempt to talk to a disconnected
> > agent is either a programming error that should be fixed (if the caller knows
> > that in time) or it's internally a valid condition that deserves at least one
> > real error message but no [soft] assertions afterwards.
> 
> Please ignore, wrong bug report.
> 
> Btw, dcbw/need-secrets doesn't exist, is it merged already or renamed?

It's a branch of network-manager-vpnc in gnome git (bug is filed against the "VPNC" component of NM) though I shoudl have specified the git repo in the initial comment.
Comment 7 Dan Williams 2013-07-14 16:14:27 UTC
danw's comments addressed; branch repushed.
Comment 8 Dan Williams 2013-07-15 15:25:53 UTC
Renamed the NeedSecrets signal to SecretsRequested.
Comment 9 Dan Williams 2013-07-15 15:26:18 UTC
(In reply to comment #8)
> Renamed the NeedSecrets signal to SecretsRequested.

Nevermind; this is for NM not vpnc.
Comment 10 Dan Winship 2013-07-16 14:09:08 UTC
this is sort of blocked until we figure out exactly what changes are going to be made to vpnc
Comment 11 Dan Williams 2013-07-21 15:13:32 UTC
Re-pushed with fixes for ConnectAsyncAllowed().
Comment 12 Dan Winship 2013-07-25 20:14:55 UTC
the newly-commented utils_handle_output() is a lot better

(random minor thing: you say "semicolon" instead of "colon" in one comment)

>+	/* Note: if vpnc sent a server message ending with ':' but we
>+	 * happened to only read up to the ':' but not the EOL, we'll
>+	 * confuse the server message with an input prompt.  vpnc is not
>+	 * helpful here.
>+	 */

or if there happens to be a ':' at byte 512. Changing data_available() to have two loops (first read in a loop until bytes_read==0, then utils_handle_output() in a loop until consumed==0) would make both cases less likely.

vpnc_check_version() will reject 0.6.2 on the grounds that 2 < 4. You need to break out early (with use_interactive = TRUE) if major > 0 or minor > 5.

It's also weird that vpnc_check_version() both returns a value and sets a global variable...


Otherwise, looks good, assuming the vpnc patches go in. I don't think we should commit this before that though.
Comment 13 Dan Williams 2013-08-12 16:42:46 UTC
*** Bug 584690 has been marked as a duplicate of this bug. ***
Comment 14 Dan Williams 2013-12-13 20:09:57 UTC
Rebased, repushed, and fixed up for most recent upstream vpnc changes.  Upstream requested that CTRL-D be used instead of CTRL-Z, and I fixed a bug or two as well.
Comment 15 Dan Winship 2013-12-23 22:10:19 UTC
basically looks good


> core: add function and testcase to parse vpnc stdout/stderr

>+		if (g_ascii_isspace (output->str[0]) || (i == 1 && IS_EOL (output->str[i])))
>+			    *server_message_done = TRUE;

Hm... why is that "i == 1" rather than "i == 0" ?

>+	 * ...  vpnc is not
>+	 * helpful here.
>+	 */

so I should have thought of this before, but if we have to patch vpnc anyway, couldn't we make it be more helpful in --interactive-stdin mode?


> core: parse vpnc stdin/stdout and request secrets asynchronously

>+	char end[] = { CEOT };

I think 0x04 would be more obvious... I don't think most people know the ASCII control character names, and if you don't know that, then it's not obvious that that's even what that is...

(I think it's also slightly weird to use ^D in this context given that it's NOT end-of-file... but I guess that's up to upstream.)

>+	lines = g_strsplit_set (output, "\n", -1);
...
>+			versions = g_strsplit_set (p, ".", -1);

g_strsplit() would be more idiomatic there. (g_strsplit_set() means "split on any of the provided characters", so it's weird to use it and pass only one character.)
Comment 16 Dan Williams 2014-08-29 20:56:42 UTC
(In reply to comment #15)
> > core: add function and testcase to parse vpnc stdout/stderr
> 
> >+		if (g_ascii_isspace (output->str[0]) || (i == 1 && IS_EOL (output->str[i])))
> >+			    *server_message_done = TRUE;
> 
> Hm... why is that "i == 1" rather than "i == 0" ?

I think it was meant to capture the case where the previous for() loop had exited after parsing 1 character, but it's easier to just do:

    if (g_ascii_isspace (output->str[0]) || IS_EOL (output->str[0]))

I think, and that still passes the testcases.  The intent with this if() is to terminate reading the server message if a blank line is found.

> >+	 * ...  vpnc is not
> >+	 * helpful here.
> >+	 */
> 
> so I should have thought of this before, but if we have to patch vpnc anyway,
> couldn't we make it be more helpful in --interactive-stdin mode?

It turns out that upstream fixed things so that there is no --interactive-stdin option anymore, it Just Works (more or less) now.  So while we could patch vpnc, upstream is already 100% ready for this already.

> > core: parse vpnc stdin/stdout and request secrets asynchronously
> 
> >+	char end[] = { CEOT };
> 
> I think 0x04 would be more obvious... I don't think most people know the ASCII
> control character names, and if you don't know that, then it's not obvious that
> that's even what that is...

Fixed.

> (I think it's also slightly weird to use ^D in this context given that it's NOT
> end-of-file... but I guess that's up to upstream.)

I'd originally used ^Z but upstream had this to say during patch review:

---------
Ctrl-Z is a DOS/Windows convension.
Ctrl-D as first char of a line is more suitable in Unix world
http://en.wikipedia.org/wiki/End-of-file
I do not have specific preference, but comments are welcome

Would be good to have a note about this new behavior in man-page.

Instead of using magic number, consider including
  sys/ttydefaults.h
and use the macros CEOF for Ctrl-D or CSUPS for Ctrl-Z.
--------

CEOF actually equals CEOT in sys/ttydefaults.h so I think I went with CEOT because it was the base identifier. 

> >+	lines = g_strsplit_set (output, "\n", -1);
> ...
> >+			versions = g_strsplit_set (p, ".", -1);
> 
> g_strsplit() would be more idiomatic there. (g_strsplit_set() means "split on
> any of the provided characters", so it's weird to use it and pass only one
> character.)

Done.

I've also rebased on git master and fixed everything up for the final implementation of the patches that upstream pushed to the SVN repo.
Comment 17 Dan Winship 2014-09-11 15:02:56 UTC
> core: parse vpnc stdin/stdout and request secrets asynchronously

> This requires vpnc SVN 550 or later.

The code and comments say "0.5.4 or later"... is that still accurate?

>	fprintf (pipe->error ? stderr : stdout, "%.*s", (int) bytes_read, buf);

Everywhere you check pipe->error, you do "pipe->error ? stderr : stdout". You should just have a FILE* member of Pipe rather than "gboolean error".

>+	if (kill (priv->pid, SIGTERM) == 0)
>+		g_timeout_add (2000, ensure_killed, GINT_TO_POINTER (priv->pid));
>+	else
>+		kill (priv->pid, SIGKILL);

according to the man page, kill() can only fail if the signal number is invalid (which we know isn't the case here), the pid is invalid, or you don't have permissions. So sending SIGKILL if the first kill() fails isn't going to help.

>+	priv->infd = -1;
>+	vpnc_cleanup (plugin, FALSE);

doesn't this leak infd? (if it wasn't already -1)

>+		char *joined = g_strjoinv (",", (char **) hints);
>+		g_message ("Requesting new secrets: '%s' (%s)", prompt, joined);

kind of overkill to call g_strjoinv since you know there's only one element in the array.

>+data_available (GIOChannel *source,

I think this will get stuck in an infinite loop on EOF. (It will read, get back G_IO_STATUS_EOF, and return TRUE, and then get called again in the next main loop iteration.)

>+	char *pwhelper_args = NULL;

>+	g_free (pwhelper_args);

not used any more

>+vpnc_check_version (void)

+		num = strtol (versions[0], NULL, 10);
+		if (errno || num < 0 || num > 1000)
+			break;
+
+		/* Fail if minor version < 5 */

You need to set interactive_available=TRUE and break if major > 0. And likewise, if major == 0 and minor > 5.

>+		/* Fail if micro version < 4 */
>+		errno = 0;
>+		num = strtol (versions[2], NULL, 10);
>+		if (errno || num < 3 || num > 1000)

"3" should be "4" in the last line
Comment 18 Dan Williams 2014-09-26 22:08:41 UTC
(In reply to comment #17)
> > core: parse vpnc stdin/stdout and request secrets asynchronously
> 
> > This requires vpnc SVN 550 or later.
> 
> The code and comments say "0.5.4 or later"... is that still accurate?

0.5.4 would be the first version that has the fixes, but upstream moves slowly so the version is still 0.5.3.  So it's still accurate.

> >	fprintf (pipe->error ? stderr : stdout, "%.*s", (int) bytes_read, buf);
> 
> Everywhere you check pipe->error, you do "pipe->error ? stderr : stdout". You
> should just have a FILE* member of Pipe rather than "gboolean error".

Done.

> >+	if (kill (priv->pid, SIGTERM) == 0)
> >+		g_timeout_add (2000, ensure_killed, GINT_TO_POINTER (priv->pid));
> >+	else
> >+		kill (priv->pid, SIGKILL);
> 
> according to the man page, kill() can only fail if the signal number is invalid
> (which we know isn't the case here), the pid is invalid, or you don't have
> permissions. So sending SIGKILL if the first kill() fails isn't going to help.

Fixed.

> >+	priv->infd = -1;
> >+	vpnc_cleanup (plugin, FALSE);
> 
> doesn't this leak infd? (if it wasn't already -1)

I can't recall why that was there.  Removed.

> >+		char *joined = g_strjoinv (",", (char **) hints);
> >+		g_message ("Requesting new secrets: '%s' (%s)", prompt, joined);
> 
> kind of overkill to call g_strjoinv since you know there's only one element in
> the array.

True, fixed.

> >+data_available (GIOChannel *source,
> 
> I think this will get stuck in an infinite loop on EOF. (It will read, get back
> G_IO_STATUS_EOF, and return TRUE, and then get called again in the next main
> loop iteration.)

I fixed this up too, now the returns FALSE from the GIOFunc.

> >+	char *pwhelper_args = NULL;
> 
> >+	g_free (pwhelper_args);
> 
> not used any more

Fixed.

> >+vpnc_check_version (void)
> 
> +        num = strtol (versions[0], NULL, 10);
> +        if (errno || num < 0 || num > 1000)
> +            break;
> +
> +        /* Fail if minor version < 5 */
> 
> You need to set interactive_available=TRUE and break if major > 0. And
> likewise, if major == 0 and minor > 5.
> 
> >+		/* Fail if micro version < 4 */
> >+		errno = 0;
> >+		num = strtol (versions[2], NULL, 10);
> >+		if (errno || num < 3 || num > 1000)
> 
> "3" should be "4" in the last line

I found a better way, which is looking for "--password-helper" which was added the same time as all the interactive fixes, so I fixed up the code to just look for that instead of trying to parse the version and stuff.

Repushed.
Comment 19 Dan Winship 2014-09-29 13:47:10 UTC
>+		if (strstr (output, "--password-helper <executable>"))

I'd check for just the "--password-helper" part, in case the "<executable>" part gets rewritten or localized later.

Everything else looks good.
Comment 20 Dan Williams 2014-09-29 14:37:58 UTC
Fixed the password-helper bit and merged to master.