[libvirt] [PATCH 0/5] Unify check for auth and auth->cb

Hi guys, in some drivers, auth and auth->cb are checked in connectOpen function, while in xenapi, only auth is checked, which that could lead to a problem if cb if invalid. In phyp, auth and auth->cb are checked twice, in getUser and getPassword. So, this patchset adds the check for auth and auth->cb inside virAuthGetUsername and virAuthGetPassword, making it safer for all drivers that rely in auth callbacks. Marcos Paulo de Souza (5): virauth.c: Check for valid auth callback esx: Drop check for auth and auth->cb hyperv: Drop check for auth and auth->cb phyp: Drop check for auth and auth->cb xenapi: Drop check for auth src/esx/esx_driver.c | 7 ------- src/hyperv/hyperv_driver.c | 7 ------- src/phyp/phyp_driver.c | 11 ----------- src/util/virauth.c | 12 ++++++++++++ src/xenapi/xenapi_driver.c | 6 ------ 5 files changed, 12 insertions(+), 31 deletions(-) -- 2.17.1

Instead of adding the same check for every drivers, execute the checks in virAuthGetUsername and virAuthGetPassword. These funtions are called when user is not set in the URI. Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com> --- src/util/virauth.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/util/virauth.c b/src/util/virauth.c index 8c450b6b31..759b8f0cd3 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -198,6 +198,12 @@ virAuthGetUsername(virConnectPtr conn, if (virAuthGetConfigFilePath(conn, &path) < 0) return NULL; + if (!auth || !auth->cb) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Missing or invalid auth pointer")); + return NULL; + } + return virAuthGetUsernamePath(path, auth, servicename, defaultUsername, hostname); } @@ -262,5 +268,11 @@ virAuthGetPassword(virConnectPtr conn, if (virAuthGetConfigFilePath(conn, &path) < 0) return NULL; + if (!auth || !auth->cb) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Missing or invalid auth pointer")); + return NULL; + } + return virAuthGetPasswordPath(path, auth, servicename, username, hostname); } -- 2.17.1

On 08/02/2018 08:27 PM, Marcos Paulo de Souza wrote:
Instead of adding the same check for every drivers, execute the checks in virAuthGetUsername and virAuthGetPassword. These funtions are called when user is not set in the URI.
Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com> --- src/util/virauth.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
I believe the virAuthGet{Username|Password}Path API's should be adjusted instead. Although not possible today as shown by the subsequent patches, if @auth or !auth->cb were NULL calling virAuthGetCredential and returning something is still possible since neither auth nor auth->cb is referenced. They are only referenced when it's required to ask via some mechanism. It's at those points we should generate the errors. Furthermore, the callers that generate their own errors based on where in the code they fail; however, those errors would hide memory allocation failures from say virAsprintf or VIR_STRDUP calls from other virAuth* APIs that are called. For example, calling virAuthGetConfigFilePathURI and failing to allocate memory would generate a memory allocation failure; however, the caller could overwrite that with a "{Username|Password} request failed" error message. Interestingly, the virAuthGetUsernamePath caller expects the error to be generated and doesn't generate it's own, but virAuthGetPasswordPath callers will generate (and overwrite) their own error. So, I think all of the error generation can be done in the *Path API's and a lot more cleanup is possible... First, just before the memset(&cred) (in both UsernamePath and PasswordPath) add the logic that would check and error for "if (!auth) {" with an error message such as "Missing authentication credentials" using VIR_ERR_INVALID_ARG for virReportError and return NULL. Next, checking and erroring for !auth->cb would only be necessary if we ever get past the credtype "continue;" condition. In that case the error message would be "Missing authentication callback" using VIR_ERR_INVALID_ARG for virReportError and return NULL. With those errors in place, there would be two more reasons that the caller would need to generate an error... First if there was no expected credtype for the API or if the (*cred->cb) returns < 0. Since the for loop breaks once the auth->cb is called, if we change the "break;" to a return cred.result and then instead of the bare return cred.result at the bottom we turn that into an error "Missing XXX credential type" (where XXX would be replaced by "VIR_CRED_AUTHNAME" and "VIR_CRED_PASSPHRASE or VIR_CRED_NOECHOPROMPT" using VIR_ERR_AUTH_FAILED for virReportError followed by return NULL. With that in place, add error processing to the auth->cb, either: virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed")); or virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed")); when (*auth->cb) < 0 Once the above is all in place, then the callers could be adjusted to not generate any errors for !auth, !auth->cb, and NULL return from the function. Take the opportunity to clean up the callers a bit to alter long lines and the calls to be just: if (!(xxxx = virAuthGet*(...))) goto xxxx; where the virAuthGet* call could be across multiple lines if it goes beyond the 80 cols, but the open/close parens {} aren't needed. The commit messages for the subsequent patches would need to be adjusted to note that you're removing the need to generate error messages for the virAuthGet{Username|Password}[Path] callers since the API's handle that. The test_driver and rpc/virnet*session.c callers do have different messages on NULL failures now, but (famous last words) that shouldn't be a problem. NB: The rpc/virnet[lib]sshsession.c consumers already do the !auth || !auth->cb checks in the form of "if (!sess->cred || !sess->cred->cb) {". I would just keep those as is. Finally, not sure how it's called, but xenapiUtil_RequestPassword would perhaps need similar adjustments. If it's caller still overwrites the message, then at least the message is logged in a domain log file somewhere. Hopefully this makes sense. This one patch is blossoming into many more and the subsequent patches get a bit more code removal using the common error messages. John
diff --git a/src/util/virauth.c b/src/util/virauth.c index 8c450b6b31..759b8f0cd3 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -198,6 +198,12 @@ virAuthGetUsername(virConnectPtr conn, if (virAuthGetConfigFilePath(conn, &path) < 0) return NULL;
+ if (!auth || !auth->cb) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Missing or invalid auth pointer")); + return NULL; + } + return virAuthGetUsernamePath(path, auth, servicename, defaultUsername, hostname);
Could have taken the opportunity to fix the indention issue caused by commit '12614e7e2' (e.g. s/defaultUsername/ defaultUsername/), but with the above suggestions that would need a separate/unnecessary patch. We'll just have to wait until someone comes this way again.
} @@ -262,5 +268,11 @@ virAuthGetPassword(virConnectPtr conn, if (virAuthGetConfigFilePath(conn, &path) < 0) return NULL;
+ if (!auth || !auth->cb) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Missing or invalid auth pointer")); + return NULL; + } + return virAuthGetPasswordPath(path, auth, servicename, username, hostname); }

On Tue, Aug 14, 2018 at 10:53:50AM -0400, John Ferlan wrote:
On 08/02/2018 08:27 PM, Marcos Paulo de Souza wrote:
Instead of adding the same check for every drivers, execute the checks in virAuthGetUsername and virAuthGetPassword. These funtions are called when user is not set in the URI.
Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com> --- src/util/virauth.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
I believe the virAuthGet{Username|Password}Path API's should be adjusted instead.
Although not possible today as shown by the subsequent patches, if @auth or !auth->cb were NULL calling virAuthGetCredential and returning something is still possible since neither auth nor auth->cb is referenced. They are only referenced when it's required to ask via some mechanism. It's at those points we should generate the errors.
Furthermore, the callers that generate their own errors based on where in the code they fail; however, those errors would hide memory allocation failures from say virAsprintf or VIR_STRDUP calls from other virAuth* APIs that are called.
For example, calling virAuthGetConfigFilePathURI and failing to allocate memory would generate a memory allocation failure; however, the caller could overwrite that with a "{Username|Password} request failed" error message.
Interestingly, the virAuthGetUsernamePath caller expects the error to be generated and doesn't generate it's own, but virAuthGetPasswordPath callers will generate (and overwrite) their own error.
So, I think all of the error generation can be done in the *Path API's and a lot more cleanup is possible...
First, just before the memset(&cred) (in both UsernamePath and PasswordPath) add the logic that would check and error for "if (!auth) {" with an error message such as "Missing authentication credentials" using VIR_ERR_INVALID_ARG for virReportError and return NULL.
Next, checking and erroring for !auth->cb would only be necessary if we ever get past the credtype "continue;" condition. In that case the error message would be "Missing authentication callback" using VIR_ERR_INVALID_ARG for virReportError and return NULL.
With those errors in place, there would be two more reasons that the caller would need to generate an error... First if there was no expected credtype for the API or if the (*cred->cb) returns < 0.
Since the for loop breaks once the auth->cb is called, if we change the "break;" to a return cred.result and then instead of the bare return cred.result at the bottom we turn that into an error "Missing XXX credential type" (where XXX would be replaced by "VIR_CRED_AUTHNAME" and "VIR_CRED_PASSPHRASE or VIR_CRED_NOECHOPROMPT" using VIR_ERR_AUTH_FAILED for virReportError followed by return NULL.
With that in place, add error processing to the auth->cb, either:
virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
or
virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
when (*auth->cb) < 0
Once the above is all in place, then the callers could be adjusted to not generate any errors for !auth, !auth->cb, and NULL return from the function. Take the opportunity to clean up the callers a bit to alter long lines and the calls to be just:
if (!(xxxx = virAuthGet*(...))) goto xxxx;
where the virAuthGet* call could be across multiple lines if it goes beyond the 80 cols, but the open/close parens {} aren't needed.
The commit messages for the subsequent patches would need to be adjusted to note that you're removing the need to generate error messages for the virAuthGet{Username|Password}[Path] callers since the API's handle that. The test_driver and rpc/virnet*session.c callers do have different messages on NULL failures now, but (famous last words) that shouldn't be a problem.
NB: The rpc/virnet[lib]sshsession.c consumers already do the !auth || !auth->cb checks in the form of "if (!sess->cred || !sess->cred->cb) {". I would just keep those as is.
Finally, not sure how it's called, but xenapiUtil_RequestPassword would perhaps need similar adjustments. If it's caller still overwrites the message, then at least the message is logged in a domain log file somewhere.
Hopefully this makes sense. This one patch is blossoming into many more and the subsequent patches get a bit more code removal using the common error messages.
John
diff --git a/src/util/virauth.c b/src/util/virauth.c index 8c450b6b31..759b8f0cd3 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -198,6 +198,12 @@ virAuthGetUsername(virConnectPtr conn, if (virAuthGetConfigFilePath(conn, &path) < 0) return NULL;
+ if (!auth || !auth->cb) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Missing or invalid auth pointer")); + return NULL; + } + return virAuthGetUsernamePath(path, auth, servicename, defaultUsername, hostname);
Could have taken the opportunity to fix the indention issue caused by commit '12614e7e2' (e.g. s/defaultUsername/ defaultUsername/), but with the above suggestions that would need a separate/unnecessary patch. We'll just have to wait until someone comes this way again.
Indeed, that was my plan, to land incremental patches to cleanup the virAuthGet* interfaces, but it seems that you already did :) Now I will try to find another places to fix and inprove inside libvirt!
} @@ -262,5 +268,11 @@ virAuthGetPassword(virConnectPtr conn, if (virAuthGetConfigFilePath(conn, &path) < 0) return NULL;
+ if (!auth || !auth->cb) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Missing or invalid auth pointer")); + return NULL; + } + return virAuthGetPasswordPath(path, auth, servicename, username, hostname); }
-- Thanks, Marcos

Since they are done inside virAuthGetPassword and virAuthGetUsername when needed. Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com> --- src/esx/esx_driver.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index c2154799fa..15785858c6 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -854,13 +854,6 @@ esxConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, conn->uri->path, conn->uri->scheme); } - /* Require auth */ - if (!auth || !auth->cb) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("Missing or invalid auth pointer")); - return VIR_DRV_OPEN_ERROR; - } - /* Allocate per-connection private data */ if (VIR_ALLOC(priv) < 0) goto cleanup; -- 2.17.1

Since they are done inside virAuthGetPassword and virAuthGetUsername when needed. Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com> --- src/hyperv/hyperv_driver.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 6bc4c099e2..7ca145aef5 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -128,13 +128,6 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); - /* Require auth */ - if (auth == NULL || auth->cb == NULL) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("Missing or invalid auth pointer")); - return VIR_DRV_OPEN_ERROR; - } - /* Allocate per-connection private data */ if (VIR_ALLOC(priv) < 0) goto cleanup; -- 2.17.1

Since they are done inside virAuthGetPassword and virAuthGetUsername when needed. Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com> --- src/phyp/phyp_driver.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index d78de83231..5b17508dae 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -957,12 +957,6 @@ openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, if (VIR_STRDUP(username, conn->uri->user) < 0) goto err; } else { - if (auth == NULL || auth->cb == NULL) { - virReportError(VIR_ERR_AUTH_FAILED, - "%s", _("No authentication callback provided.")); - goto err; - } - username = virAuthGetUsername(conn, auth, "ssh", NULL, conn->uri->server); if (username == NULL) { @@ -1039,11 +1033,6 @@ openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, if (rc == LIBSSH2_ERROR_SOCKET_NONE || rc == LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED || rc == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) { - if (auth == NULL || auth->cb == NULL) { - virReportError(VIR_ERR_AUTH_FAILED, - "%s", _("No authentication callback provided.")); - goto disconnect; - } password = virAuthGetPassword(conn, auth, "ssh", username, conn->uri->server); -- 2.17.1

Since they are done inside virAuthGetPassword and virAuthGetUsername when needed. Also, only auth is checked, but auth->cb, which that could lead to a crash if the callback is NULL. Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com> --- src/xenapi/xenapi_driver.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 34f9e2c717..3af5eeafcf 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -152,12 +152,6 @@ xenapiConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, goto error; } - if (auth == NULL) { - xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED, - _("Authentication Credentials not found")); - goto error; - } - if (conn->uri->user != NULL) { if (VIR_STRDUP(username, conn->uri->user) < 0) goto error; -- 2.17.1

On 08/03/2018 02:27 AM, Marcos Paulo de Souza wrote:
Hi guys,
in some drivers, auth and auth->cb are checked in connectOpen function, while in xenapi, only auth is checked, which that could lead to a problem if cb if invalid. In phyp, auth and auth->cb are checked twice, in getUser and getPassword.
So, this patchset adds the check for auth and auth->cb inside virAuthGetUsername and virAuthGetPassword, making it safer for all drivers that rely in auth callbacks.
Marcos Paulo de Souza (5): virauth.c: Check for valid auth callback esx: Drop check for auth and auth->cb hyperv: Drop check for auth and auth->cb phyp: Drop check for auth and auth->cb xenapi: Drop check for auth
src/esx/esx_driver.c | 7 ------- src/hyperv/hyperv_driver.c | 7 ------- src/phyp/phyp_driver.c | 11 ----------- src/util/virauth.c | 12 ++++++++++++ src/xenapi/xenapi_driver.c | 6 ------ 5 files changed, 12 insertions(+), 31 deletions(-)
ACKed and pushed. Michal
participants (3)
-
John Ferlan
-
Marcos Paulo de Souza
-
Michal Privoznik