From a8d29b1e7e407d5c69b50e64054dae76f2660076 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 7 Mar 2021 15:34:26 +0100 Subject: [PATCH] * Restconf authentication callback (ca_auth) signature changed * Not backward compatible: All uses of the ca-auth callback in restconf plugins must be changed * New version is: `int ca_auth(h, req, auth_type, authp, userp)` * where `auth_type` is the requested authentication-type (none, client-cert or user-defined) * `authp` is the returned authentication flag * `userp` is the returned associated authenticated user * and the return value is three-valued: -1: Error, 0: not handled, 1: OK * For more info see [clixon-docs/restconf](https://clixon-docs.readthedocs.io/en/latest/restconf.html) --- CHANGELOG.md | 10 ++++++ apps/restconf/restconf_lib.c | 7 ++-- example/main/example_restconf.c | 64 ++++++++++++++++----------------- lib/clixon/clixon_plugin.h | 12 ++++--- lib/src/clixon_plugin.c | 39 +++++++++----------- 5 files changed, 69 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a526af29..d31c6a28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,16 @@ ## 5.1.0 Expected: April +### C/CLI-API changes on existing features + +Developers may need to change their code + +* Restconf authentication callback (ca_auth) signature changed (again) + * Minor modification to 5.0 change: userp removed. + * New version is: `int ca_auth(h, req, auth_type, authp)`, where + * `authp` is NULL for not authenticated, or the returned associated authenticated user + * For more info see [clixon-docs/restconf](https://clixon-docs.readthedocs.io/en/latest/restconf.html) + ### Minor features * Made a separate Clixon datastore XML/JSON top-level symbol diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index 4be5e0a3..c83bbd6d 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -513,7 +513,7 @@ restconf_authentication_cb(clicon_handle h, clixon_auth_type_t auth_type; int authenticated; int ret; - char *username = NULL; + char *username = NULL; /* Assume malloced if set */ cxobj *xret = NULL; cxobj *xerr; char *anonymous = NULL; @@ -525,12 +525,13 @@ restconf_authentication_cb(clicon_handle h, /* ret: -1 Error, 0: Ignore/not handled, 1: OK see authenticated parameter */ if ((ret = clixon_plugin_auth_all(h, req, auth_type, - &authenticated, &username)) < 0) goto done; if (ret == 1){ /* OK, tag username to handle */ - if (authenticated == 1) + if (username != NULL){ + authenticated = 1; clicon_username_set(h, username); + } } else { /* Default behaviour */ switch (auth_type){ diff --git a/example/main/example_restconf.c b/example/main/example_restconf.c index 2f5908fe..ce00c98b 100644 --- a/example/main/example_restconf.c +++ b/example/main/example_restconf.c @@ -189,19 +189,19 @@ b64_decode(const char *src, /*! HTTP basic authentication example (note hardwired) * @param[in] h Clicon handle * @param[in] req Per-message request www handle to use with restconf_api.h - * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set - * @param[out] userp If retval is OK and auth=1, the associated user, malloced by plugin + * @param[out] authp NULL: Credentials failed, no user set (401 returned). + * String: Credentials OK, the associated user, must be mallloc:ed + * Parameter signtificant only if retval is 1/OK * @retval -1 Fatal error * @retval 0 Ignore, undecided, not handled, same as no callback - * @retval 1 OK, see auth parameter on result. - * @note user should be malloced + * @retval 1 OK, see authp parameter for result. + * @note authp should be malloced * @note: Three hardwired users: andy, wilma, guest w password "bar". */ static int example_basic_auth(clicon_handle h, void *req, - int *authp, - char **userp) + char **authp) { int retval = -1; cxobj *xt = NULL; @@ -214,8 +214,8 @@ example_basic_auth(clicon_handle h, int ret; clicon_debug(1, "%s", __FUNCTION__); - if (authp == NULL || userp == NULL){ - clicon_err(OE_PLUGIN, EINVAL, "Output parameter is NULL"); + if (authp == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "Authp output parameter is NULL"); goto done; } /* At this point in the code we must use HTTP basic authentication */ @@ -250,12 +250,11 @@ example_basic_auth(clicon_handle h, } if (strcmp(passwd, passwd2)) goto fail; - *userp = user; /* authenticated */ + *authp = user; /* authenticated */ user=NULL; /* to avoid free below */ - *authp = 1; retval = 1; done: /* error */ - clicon_debug(1, "%s retval:%d authp:%d userp:%s", __FUNCTION__, retval, *authp, *userp); + clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, *authp); if (user) free(user); if (cb) @@ -264,7 +263,7 @@ example_basic_auth(clicon_handle h, xml_free(xt); return retval; fail: /* unauthenticated */ - *authp = 0; + *authp = NULL; retval = 1; goto done; } @@ -272,18 +271,18 @@ example_basic_auth(clicon_handle h, /*! HTTP "no auth" but uses basic authentication to get a user * @param[in] h Clicon handle * @param[in] req Per-message request www handle to use with restconf_api.h - * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set - * @param[out] userp If retval is OK and auth=1, the associated user, malloced by plugin + * @param[out] authp NULL: Credentials failed, no user set (401 returned). + * String: Credentials OK, the associated user, must be mallloc:ed + * Parameter signtificant only if retval is 1/OK * @retval -1 Fatal error * @retval 0 Ignore, undecided, not handled, same as no callback - * @retval 1 OK, see auth parameter on result. - * @note user should be malloced + * @retval 1 OK, see authp parameter for result. + * @note authp should be malloced */ static int example_no_auth(clicon_handle h, void *req, - int *authp, - char **userp) + char **authp) { int retval = -1; cxobj *xt = NULL; @@ -295,8 +294,8 @@ example_no_auth(clicon_handle h, int ret; clicon_debug(1, "%s", __FUNCTION__); - if (authp == NULL || userp == NULL){ - clicon_err(OE_PLUGIN, EINVAL, "Output parameter is NULL"); + if (authp == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "Authp output parameter is NULL"); goto done; } /* At this point in the code we must use HTTP basic authentication */ @@ -321,12 +320,11 @@ example_no_auth(clicon_handle h, *passwd = '\0'; passwd++; clicon_debug(1, "%s http user:%s passwd:%s", __FUNCTION__, user, passwd); - *userp = user; /* authenticated */ + *authp = user; /* authenticated */ user=NULL; /* to avoid free below */ - *authp = 1; retval = 1; done: /* error */ - clicon_debug(1, "%s retval:%d authp:%d userp:%s", __FUNCTION__, retval, *authp, *userp); + clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, *authp); if (user) free(user); if (cb) @@ -335,7 +333,7 @@ example_no_auth(clicon_handle h, xml_free(xt); return retval; fail: /* unauthenticated */ - *authp = 0; + *authp = NULL; retval = 0; /* Ignore use anonymous */ goto done; } @@ -344,38 +342,38 @@ example_no_auth(clicon_handle h, * @param[in] h Clicon handle * @param[in] req Per-message request www handle to use with restconf_api.h * @param[in] auth_type Authentication type: none, user-defined, or client-cert - * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set - * @param[out] userp The associated user, malloced by plugin. Only if retval is 1/OK and authp=1, + * @param[out] authp NULL: Credentials failed, no user set (401 returned). + * String: Credentials OK, the associated user, must be mallloc:ed + * Parameter signtificant only if retval is 1/OK * @retval -1 Fatal error * @retval 0 Ignore, undecided, not handled, same as no callback - * @retval 1 OK, see auth parameter on result. - * @note user should be malloced + * @retval 1 OK, see authp parameter for result. + * @note authp should be malloced */ int example_restconf_credentials(clicon_handle h, void *req, clixon_auth_type_t auth_type, - int *authp, - char **userp) + char **authp) { int retval = -1; clicon_debug(1, "%s auth:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type)); switch (auth_type){ case CLIXON_AUTH_NONE: - if ((retval = example_no_auth(h, req, authp, userp)) < 0) + if ((retval = example_no_auth(h, req, authp)) < 0) goto done; break; case CLIXON_AUTH_CLIENT_CERTIFICATE: retval = 0; /* Ignore, use default */ break; case CLIXON_AUTH_USER: - if ((retval = example_basic_auth(h, req, authp, userp)) < 0) + if ((retval = example_basic_auth(h, req, authp)) < 0) goto done; break; } done: - clicon_debug(1, "%s retval:%d auth:%d user:%s", __FUNCTION__, retval, *authp, *userp); + clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, *authp); return retval; } diff --git a/lib/clixon/clixon_plugin.h b/lib/clixon/clixon_plugin.h index 302befab..2930a8d8 100644 --- a/lib/clixon/clixon_plugin.h +++ b/lib/clixon/clixon_plugin.h @@ -174,15 +174,17 @@ typedef int (plgextension_t)(clicon_handle h, yang_stmt *yext, yang_stmt *ys); * @param[in] h Clicon handle * @param[in] req Per-message request www handle to use with restconf_api.h * @param[in] auth_type Authentication type: none, user-defined, or client-cert - * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set - * @param[out] userp The associated user, malloced by plugin. Only if retval is 1/OK and authp=1, + * @param[out] authp NULL: Credentials failed, no user set (401 returned). + * String: Credentials OK, the associated user, must be mallloc:ed + * Parameter signtificant only if retval is 1/OK * @retval -1 Fatal error * @retval 0 Ignore, undecided, not handled, same as no callback - * @retval 1 OK, see auth parameter on result. + * @retval 1 OK, see authp parameter for result. + * @note If authp returns string, it should be malloced * * @note user should be freed by caller */ -typedef int (plgauth_t)(clicon_handle h, void *req, clixon_auth_type_t auth_type, int *authp, char **userp); +typedef int (plgauth_t)(clicon_handle h, void *req, clixon_auth_type_t auth_type, char **authp); /*! Reset system status * @param[in] h Clicon handle @@ -345,7 +347,7 @@ int clixon_plugin_start_all(clicon_handle h); int clixon_plugin_exit_one(clixon_plugin *cp, clicon_handle h); int clixon_plugin_exit_all(clicon_handle h); -int clixon_plugin_auth_all(clicon_handle h, void *req, clixon_auth_type_t auth_type, int *authp, char **userp); +int clixon_plugin_auth_all(clicon_handle h, void *req, clixon_auth_type_t auth_type, char **authp); int clixon_plugin_extension_one(clixon_plugin *cp, clicon_handle h, yang_stmt *yext, yang_stmt *ys); int clixon_plugin_extension_all(clicon_handle h, yang_stmt *yext, yang_stmt *ys); diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index 7b11af5f..6b2edf43 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -467,11 +467,12 @@ clixon_plugin_exit_all(clicon_handle h) * @param[in] h Clicon handle * @param[in] req Per-message request www handle to use with restconf_api.h * @param[in] auth_type Authentication type: none, user-defined, or client-cert - * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set - * @param[out] userp The associated user, malloced by plugin. Only if retval is 1/OK and authp=1, + * @param[out] authp NULL: Credentials failed, no user set (401 returned). + * String: Credentials OK, the associated user, must be mallloc:ed + * Parameter signtificant only if retval is 1/OK * @retval -1 Fatal error * @retval 0 Ignore, undecided, not handled, same as no callback - * @retval 1 OK, see auth parameter on result. + * @retval 1 OK, see authp parameter on result. * @note If authenticated either a callback was called and clicon_username_set() * Or no callback was found. */ @@ -480,15 +481,14 @@ clixon_plugin_auth_one(clixon_plugin *cp, clicon_handle h, void *req, clixon_auth_type_t auth_type, - int *authp, - char **userp) + char **authp) { int retval = -1; plgauth_t *fn; /* Plugin auth */ clicon_debug(1, "%s", __FUNCTION__); if ((fn = cp->cp_api.ca_auth) != NULL){ - if ((retval = fn(h, req, auth_type, authp, userp)) < 0) { + if ((retval = fn(h, req, auth_type, authp)) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Auth callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, cp->cp_name); @@ -498,7 +498,7 @@ clixon_plugin_auth_one(clixon_plugin *cp, else retval = 0; /* Ignored / no callback */ done: - clicon_debug(1, "%s retval:%d user:%s", __FUNCTION__, retval, *userp); + clicon_debug(1, "%s retval:%d auth:%s", __FUNCTION__, retval, *authp); return retval; } @@ -508,44 +508,39 @@ clixon_plugin_auth_one(clixon_plugin *cp, * @param[in] h Clicon handle * @param[in] req Per-message request www handle to use with restconf_api.h * @param[in] auth_type Authentication type: none, user-defined, or client-cert - * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set - * @param[out] userp The associated user, malloced by plugin. Only if retval is 1/OK and authp=1, + * @param[out] authp NULL: Credentials failed, no user set (401 returned). + * String: Credentials OK, the associated user, must be mallloc:ed + * Parameter signtificant only if retval is 1/OK * @retval -1 Fatal error * @retval 0 Ignore, undecided, not handled, same as no callback - * @retval 1 OK, see auth parameter on result. + * @retval 1 OK, see authp parameter for result. + * @note If authp returns string, it should be malloced */ int clixon_plugin_auth_all(clicon_handle h, void *req, clixon_auth_type_t auth_type, - int *authp, - char **userp) + char **authp) { int retval = -1; clixon_plugin *cp = NULL; int ret = 0; clicon_debug(1, "%s", __FUNCTION__); - if (authp == NULL || userp == NULL){ - clicon_err(OE_PLUGIN, EINVAL, "Output parameter is NULL"); + if (authp == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "Authp output parameter is NULL"); goto done; } - *authp = -1; - *userp = NULL; + *authp = NULL; ret = 0; /* ignore */ while ((cp = clixon_plugin_each(h, cp)) != NULL) { - if ((ret = clixon_plugin_auth_one(cp, h, req, auth_type, authp, userp)) < 0) + if ((ret = clixon_plugin_auth_one(cp, h, req, auth_type, authp)) < 0) goto done; if (ret == 1) break; /* result, not ignored */ /* ret == 0, ignore try next */ } retval = ret; - if (retval == 1){ - assert(*authp != -1); - if (*authp == 1) - assert(*userp != NULL); - } done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); return retval;