summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--desktop/gui_factory.c10
-rw-r--r--desktop/netsurf.c198
-rw-r--r--include/netsurf/misc.h33
3 files changed, 231 insertions, 10 deletions
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index ca9eff1da..b2b9a3bf8 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -679,10 +679,14 @@ static nserror gui_default_cert_verify(nsurl *url,
return NSERROR_NOT_IMPLEMENTED;
}
-static void gui_default_401login_open(nsurl *url, const char *realm,
- nserror (*cb)(bool proceed, void *pw), void *cbpw)
+static nserror gui_default_401login_open(nsurl *url, const char *realm,
+ const char *username, const char *password,
+ nserror (*cb)(const char *username,
+ const char *password,
+ void *pw),
+ void *cbpw)
{
- cb(false, cbpw);
+ return NSERROR_NOT_IMPLEMENTED;
}
static void
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index f39a6baef..3757a2a34 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -30,6 +30,7 @@
#include "utils/nsoption.h"
#include "utils/corestrings.h"
#include "utils/log.h"
+#include "utils/string.h"
#include "utils/utf8.h"
#include "utils/messages.h"
#include "content/content_factory.h"
@@ -94,6 +95,198 @@ static void netsurf_lwc_iterator(lwc_string *str, void *pw)
}
/**
+ * Build a "username:password" from components.
+ *
+ * \param[in] username The username component.
+ * \param[in] password The password component.
+ * \param[out] userpass_out Returns combined string on success.
+ * Owned by caller.
+ * \return NSERROR_OK, or appropriate error code.
+ */
+static nserror netsurf__build_userpass(
+ const char *username,
+ const char *password,
+ char **userpass_out)
+{
+ char *userpass;
+ size_t len;
+
+ len = strlen(username) + 1 + strlen(password) + 1;
+
+ userpass = malloc(len);
+ if (userpass == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(userpass, len, "%s:%s", username, password);
+
+ *userpass_out = userpass;
+ return NSERROR_OK;
+}
+
+/**
+ * Unpack a "username:password" to components.
+ *
+ * \param[in] userpass The input string to split.
+ * \param[in] username_out Returns username on success. Owned by caller.
+ * \param[out] password_out Returns password on success. Owned by caller.
+ * \return NSERROR_OK, or appropriate error code.
+ */
+static nserror netsurf__unpack_userpass(
+ const char *userpass,
+ char **username_out,
+ char **password_out)
+{
+ const char *tmp;
+ char *username;
+ char *password;
+ size_t len;
+
+ if (userpass == NULL) {
+ username = malloc(1);
+ password = malloc(1);
+ if (username == NULL || password == NULL) {
+ return NSERROR_NOMEM;
+ }
+ username[0] = '\0';
+ password[0] = '\0';
+
+ *username_out = username;
+ *password_out = password;
+ return NSERROR_OK;
+ }
+
+ tmp = strchr(userpass, ':');
+ if (tmp == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ } else {
+ size_t len2;
+ len = tmp - userpass;
+ len2 = strlen(++tmp);
+
+ username = malloc(len + 1);
+ password = malloc(len2 + 1);
+ if (username == NULL || password == NULL) {
+ return NSERROR_NOMEM;
+ }
+ memcpy(username, userpass, len);
+ username[len] = '\0';
+ memcpy(password, tmp, len2 + 1);
+ }
+
+ *username_out = username;
+ *password_out = password;
+ return NSERROR_OK;
+}
+
+/**
+ * Contect for login callbacks to front ends.
+ */
+struct auth_data {
+ char *realm;
+ nsurl *url;
+
+ llcache_query_response cb;
+ void *pw;
+};
+
+/**
+ * Callback function passed to front ends for handling logins.
+ *
+ * \param[in] username The username.
+ * \param[in] password The password.
+ * \param[in] cbpw Our context.
+ * \return NSERROR_OK, or appropriate error code.
+ */
+static nserror netsurf__handle_login_response(
+ const char *username,
+ const char *password,
+ void *cbpw)
+{
+ struct auth_data *ctx = cbpw;
+ bool proceed = false;
+ nserror err;
+
+ if (username != NULL && password != NULL) {
+ char *userpass;
+
+ err = netsurf__build_userpass(username, password, &userpass);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
+ urldb_set_auth_details(ctx->url, ctx->realm, userpass);
+ free(userpass);
+ proceed = true;
+ }
+
+ err = ctx->cb(proceed, ctx->pw);
+ nsurl_unref(ctx->url);
+ free(ctx->realm);
+ free(ctx);
+ return err;
+}
+
+/**
+ * Helper for getting front end to handle logins.
+ *
+ * \param[in] query Query descriptor
+ * \param[in] pw Private data
+ * \param[in] cb Continuation callback
+ * \param[in] cbpw Private data for continuation
+ * \return NSERROR_OK, or appropriate error code.
+ */
+static nserror netsurf__handle_login(const llcache_query *query,
+ void *pw, llcache_query_response cb, void *cbpw)
+{
+ struct auth_data *ctx;
+ char *username;
+ char *password;
+ nserror err;
+
+ NSLOG(llcache, INFO, "HTTP Auth for: %s: %s",
+ query->data.auth.realm, nsurl_access(query->url));
+
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ ctx->realm = strdup(query->data.auth.realm);
+ if (ctx->realm == NULL) {
+ free(ctx);
+ return NSERROR_NOMEM;
+ }
+ ctx->url = nsurl_ref(query->url);
+ ctx->cb = cb;
+ ctx->pw = cbpw;
+
+ err = netsurf__unpack_userpass(
+ urldb_get_auth_details(ctx->url, ctx->realm),
+ &username, &password);
+ if (err != NSERROR_OK) {
+ nsurl_unref(ctx->url);
+ free(ctx->realm);
+ free(ctx);
+ return err;
+ }
+
+ err = guit->misc->login(ctx->url, ctx->realm, username, password,
+ netsurf__handle_login_response, ctx);
+ free(username);
+ free(password);
+ if (err != NSERROR_OK) {
+ ctx->cb(false, ctx->pw);
+ nsurl_unref(ctx->url);
+ free(ctx->realm);
+ free(ctx);
+ return err;
+ }
+
+ return NSERROR_OK;
+}
+
+/**
* Dispatch a low-level cache query to the frontend
*
* \param query Query descriptor
@@ -109,10 +302,7 @@ static nserror netsurf_llcache_query_handler(const llcache_query *query,
switch (query->type) {
case LLCACHE_QUERY_AUTH:
- NSLOG(llcache, INFO, "HTTP Auth for: %s: %s",
- query->data.auth.realm,
- nsurl_access(query->url));
- guit->misc->login(query->url, query->data.auth.realm, cb, cbpw);
+ res = netsurf__handle_login(query, pw, cb, cbpw);
break;
case LLCACHE_QUERY_REDIRECT:
diff --git a/include/netsurf/misc.h b/include/netsurf/misc.h
index 2647b9a1c..cd86cf644 100644
--- a/include/netsurf/misc.h
+++ b/include/netsurf/misc.h
@@ -91,13 +91,40 @@ struct gui_misc_table {
* \param cbpw Context pointer passed to cb
* \return NSERROR_OK on sucess else error and cb never called
*/
- nserror (*cert_verify)(struct nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw);
+ nserror (*cert_verify)(struct nsurl *url,
+ const struct ssl_cert_info *certs,
+ unsigned long num,
+ nserror (*cb)(bool proceed, void *pw),
+ void *cbpw);
/**
* Prompt user for login
+ *
+ * To cancel a login, clients should call the `cb` callback passing
+ * NULL for username, and password. Otherwise, for logins, username
+ * and password should both be non-NULL. Pass "" if the empty string
+ * is required.
+ *
+ * If the front end returns NSERROR_OK for this function, they must,
+ * at some future time, call the `cb` with `cbpw` callback exactly once.
+ *
+ * If ther front end returns other than NSERROR_OK, they should not
+ * call the `cb` callback.
+ *
+ * \param url The URL being verified.
+ * \param realm The authorization realm.
+ * \param username Any current username (or empty string).
+ * \param password Any current password (or empty string).
+ * \param cb Callback upon user decision.
+ * \param cbpw Context pointer passed to cb
+ * \return NSERROR_OK on sucess else error and cb never called
*/
- void (*login)(struct nsurl *url, const char *realm,
- nserror (*cb)(bool proceed, void *pw), void *cbpw);
+ nserror (*login)(struct nsurl *url, const char *realm,
+ const char *username, const char *password,
+ nserror (*cb)(const char *username,
+ const char *password,
+ void *pw),
+ void *cbpw);
/**
* Prompt the user for a password for a PDF.