pytorctl apparently suffers from the same problem Vidalia did in #3898 (closed), except backwards -- where Vidalia would try cookie if offered and give up if it fails, apparently pytorctl tries password if offered and gives up if it fails.
Not quite. TorCtl tries the first authentication type present in the 'METHODS=' entry. Iirc this is COOKIE if both are offered so it'll have the same issue that's discussed in 3898.
When both are offered we should:
try the password if we already have it at that point in execution (ie, it's an arg to connect)
attempt to read the cookie file and use that
prompt the user for a password
This attempts in order of relative attempt speed, prompting the user as a last resort.
Not quite. TorCtl tries the first authentication type present in the 'METHODS=' entry. Iirc this is COOKIE if both are offered so it'll have the same issue that's discussed in 3898.
When both are offered we should:
try the password if we already have it at that point in execution (ie, it's an arg to connect)
attempt to read the cookie file and use that
prompt the user for a password
This attempts in order of relative attempt speed, prompting the user as a last resort.
How can we ensure that bandwidth authorities, exit scanners, and other unattended processes that use PyTorCtl never try to 'prompt the user for a password'? (That would cause Nagios scripts to think that the process is running, even if it's doing nothing.)
preauth_connect() which just returns the auth type and unauthenticated connection, letting the caller handle that
the connection can be made manually and authenticated, which is how it was done before the above existed
If starting non-interactively is important then they shouldn't be using the connect() method.
This change will need to break backward compatibility for preauth_connect callers since the return value needs to be an auth type tuple, but arm is probably the only caller so I doubt Mike will mind much.
Tor closes its socket after a failed authentication attempt. This patch seems to work in practice because cookie auth failures are almost always with reading the cookie so we fail before issuing an AUTHENTICATE call.
However, if the auth cookie somehow contains the wrong auth value then...
torctl will send the cookie value to tor which is rejected, closing the socket
torctl will then fall back to sending the user's passphrase, which regardless of if it's correct or not will also fail because the socket is closed
From what I recall of vidalia's handling I suspect it has a similar bug. I'm attempting to address this with stem by having socket objects that can reconnect after a failed connection attempt - see the ControlSocket and sublasses of...
https://gitweb.torproject.org/stem.git/blob/HEAD:/stem/socket.py
All that said, this patch still gets TorCtl to a better place than it once was.
Oh, a bug with this patch: if the PROTOCOLINFO response has multiple auth types and the authenticate() caller doesn't provide a passphrase then we abort without trying cookie auth (see lines 1014-1016). This can be trivially fixed by changing...
if AUTH_TYPE.PASSWORD in self._authTypes and secret == "":
to
if secret == "" and self._authTypes == (AUTH_TYPE.PASSWORD,):
This probably also means an issue with the edge case where the user generated an empty password...
tor --hash-password ""
so I'd suggest changing the secret default value to None.