These are all really SoupContext functions, so move them to soup-context.c
[platform/upstream/libsoup.git] / libsoup / soup-auth.c
index c8e3305..e9615eb 100644 (file)
@@ -62,6 +62,21 @@ basic_parse_func (SoupAuth *auth, const char *header)
        soup_header_param_destroy_hash (tokens);
 }
 
+static GSList *
+basic_pspace_func (SoupAuth *auth, const SoupUri *source_uri)
+{
+       char *space, *p;
+
+       space = g_strdup (source_uri->path);
+
+       /* Strip query and filename component */
+       p = strrchr (space, '/');
+       if (p && p != space && p[1])
+               *p = '\0';
+
+       return g_slist_prepend (NULL, space);
+}
+
 static void
 basic_init_func (SoupAuth *auth, const SoupUri *uri)
 {
@@ -71,6 +86,20 @@ basic_init_func (SoupAuth *auth, const SoupUri *uri)
        user_pass = g_strdup_printf ("%s:%s", uri->user, uri->passwd);
        basic->token = soup_base64_encode (user_pass, strlen (user_pass));
        g_free (user_pass);
+
+       auth->authenticated = TRUE;
+}
+
+static gboolean
+basic_invalidate_func (SoupAuth *auth)
+{
+       SoupAuthBasic *basic = (SoupAuthBasic *) auth;
+
+       g_free (basic->token);
+       basic->token = NULL;
+       auth->authenticated = FALSE;
+
+       return TRUE;
 }
 
 static void
@@ -91,9 +120,12 @@ soup_auth_new_basic (void)
        basic = g_new0 (SoupAuthBasic, 1);
        auth = (SoupAuth *) basic;
        auth->type = SOUP_AUTH_TYPE_BASIC;
+       auth->authenticated = FALSE;
 
        auth->parse_func = basic_parse_func;
        auth->init_func = basic_init_func;
+       auth->invalidate_func = basic_invalidate_func;
+       auth->pspace_func = basic_pspace_func;
        auth->auth_func = basic_auth_func;
        auth->free_func = basic_free;
 
@@ -126,6 +158,7 @@ typedef struct {
        char *nonce;
        QOPType qop_options;
        AlgorithmType algorithm;
+       char *domain;
 
        /* These are generated by the client */
        char *cnonce;
@@ -331,6 +364,7 @@ digest_parse_func (SoupAuth *auth, const char *header)
        auth->realm = soup_header_param_copy_token (tokens, "realm");
 
        digest->nonce = soup_header_param_copy_token (tokens, "nonce");
+       digest->domain = soup_header_param_copy_token (tokens, "domain");
 
        tmp = soup_header_param_copy_token (tokens, "qop");
        ptr = tmp;
@@ -356,6 +390,50 @@ digest_parse_func (SoupAuth *auth, const char *header)
        soup_header_param_destroy_hash (tokens);
 }
 
+static GSList *
+digest_pspace_func (SoupAuth *auth, const SoupUri *source_uri)
+{
+       SoupAuthDigest *digest = (SoupAuthDigest *) auth;
+       GSList *space = NULL;
+       SoupUri *uri;
+       char *domain, *d, *lasts, *dir, *slash;
+
+       if (!digest->domain || !*digest->domain) {
+               /* If no domain directive, the protection space is the
+                * whole server.
+                */
+               return g_slist_prepend (NULL, g_strdup (""));
+       }
+
+       domain = g_strdup (digest->domain);
+       for (d = strtok_r (domain, " ", &lasts); d; d = strtok_r (NULL, " ", &lasts)) {
+               if (*d == '/')
+                       dir = g_strdup (d);
+               else {
+                       uri = soup_uri_new (d);
+                       if (uri && uri->protocol == source_uri->protocol &&
+                           uri->port == source_uri->port &&
+                           !strcmp (uri->host, source_uri->host))
+                               dir = g_strdup (uri->path);
+                       else
+                               dir = NULL;
+                       if (uri)
+                               soup_uri_free (uri);
+               }
+
+               if (dir) {
+                       slash = strrchr (dir, '/');
+                       if (slash && !slash[1])
+                               *slash = '\0';
+
+                       space = g_slist_prepend (space, dir);
+               }
+       }
+       g_free (domain);
+
+       return space;
+}
+
 static void
 digest_init_func (SoupAuth *auth, const SoupUri *uri)
 {
@@ -392,6 +470,17 @@ digest_init_func (SoupAuth *auth, const SoupUri *uri)
        /* hexify A1 */
        md5_final (&ctx, d);
        digest_hex (d, digest->hex_a1);
+
+       auth->authenticated = TRUE;
+}
+
+static gboolean
+digest_invalidate_func (SoupAuth *auth)
+{
+       /* If we failed, we need to get a new nonce from the server
+        * next time, so this can't be reused.
+        */
+       return FALSE;
 }
 
 static void
@@ -400,6 +489,7 @@ digest_free (SoupAuth *auth)
        SoupAuthDigest *digest = (SoupAuthDigest *) auth;
 
        g_free (digest->user);
+       g_free (digest->domain);
 
        g_free (digest->nonce);
        g_free (digest->cnonce);
@@ -417,9 +507,12 @@ soup_auth_new_digest (void)
 
        auth = (SoupAuth *) digest;
        auth->type = SOUP_AUTH_TYPE_DIGEST;
+       auth->authenticated = FALSE;
 
        auth->parse_func = digest_parse_func;
        auth->init_func = digest_init_func;
+       auth->invalidate_func = digest_invalidate_func;
+       auth->pspace_func = digest_pspace_func;
        auth->auth_func = digest_auth_func;
        auth->free_func = digest_free;
 
@@ -452,15 +545,14 @@ static gchar *
 ntlm_auth (SoupAuth *sa, SoupMessage *msg)
 {
        SoupAuthNTLM *auth = (SoupAuthNTLM *) sa;
-       gchar *ret;
+       char *ret;
 
-       if (sa->status == SOUP_AUTH_STATUS_PENDING)
+       if (!sa->authenticated)
                return soup_ntlm_request ();
 
        /* Otherwise, return the response; but only once */
        ret = auth->response;
        auth->response = NULL;
-
        return ret;
 }
 
@@ -495,13 +587,20 @@ ntlm_parse (SoupAuth *sa, const char *header)
        g_strstrip (auth->header);
 }
 
+static GSList *
+ntlm_pspace (SoupAuth *auth, const SoupUri *source_uri)
+{
+       /* The protection space is the whole server. */
+       return g_slist_prepend (NULL, g_strdup (""));
+}
+
 static void
 ntlm_init (SoupAuth *sa, const SoupUri *uri)
 {
        SoupAuthNTLM *auth = (SoupAuthNTLM *) sa;
        gchar *host, *domain, *nonce;
 
-       if (strlen (auth->header) < sizeof ("NTLM"))
+       if (!auth->header || strlen (auth->header) < sizeof ("NTLM"))
                return;
 
        if (auth->response)
@@ -525,14 +624,24 @@ ntlm_init (SoupAuth *sa, const SoupUri *uri)
        g_free (host);
        g_free (domain);
 
-       /* Set this now so that if the server returns 401,
-        * soup will fail instead of looping (since that
-        * probably means the password was incorrect).
-        */
-       sa->status = SOUP_AUTH_STATUS_SUCCESSFUL;
+       g_free (auth->header);
+       auth->header = NULL;
+
+       sa->authenticated = TRUE;
+}
+
+static gboolean
+ntlm_invalidate (SoupAuth *sa)
+{
+       SoupAuthNTLM *auth = (SoupAuthNTLM *) sa;
 
+       g_free (auth->response);
+       auth->response = NULL;
        g_free (auth->header);
        auth->header = NULL;
+
+       sa->authenticated = FALSE;
+       return TRUE;
 }
 
 static void
@@ -545,16 +654,20 @@ ntlm_free (SoupAuth *sa)
        g_free (auth);
 }
 
-static SoupAuth *
-ntlm_new (void)
+SoupAuth *
+soup_auth_new_ntlm (void)
 {
        SoupAuthNTLM *auth;
 
        auth = g_new0 (SoupAuthNTLM, 1);
        auth->auth.type = SOUP_AUTH_TYPE_NTLM;
+       auth->auth.authenticated = FALSE;
+       auth->auth.realm = g_strdup ("");
 
        auth->auth.parse_func = ntlm_parse;
        auth->auth.init_func = ntlm_init;
+       auth->auth.invalidate_func = ntlm_invalidate;
+       auth->auth.pspace_func = ntlm_pspace;
        auth->auth.auth_func = ntlm_auth;
        auth->auth.free_func = ntlm_free;
 
@@ -566,92 +679,6 @@ ntlm_new (void)
  * Generic Authentication Interface
  */
 
-SoupAuth *
-soup_auth_lookup (SoupContext  *ctx)
-{
-       GHashTable *auth_hash = ctx->server->valid_auths;
-       SoupAuth *ret = NULL;
-       gchar *mypath, *dir;
-
-       if (!auth_hash) return NULL;
-
-       mypath = g_strdup (ctx->uri->path);
-       dir = mypath;
-
-        do {
-                ret = g_hash_table_lookup (auth_hash, mypath);
-                if (ret) break;
-
-                dir = strrchr (mypath, '/');
-                if (dir) *dir = '\0';
-        } while (dir);
-
-       g_free (mypath);
-       return ret;
-}
-
-void
-soup_auth_invalidate (SoupAuth *auth, SoupContext *ctx)
-{
-       SoupHost *server;
-       const SoupUri *uri;
-       SoupAuth *old_auth;
-       char *old_path;
-
-       g_return_if_fail (ctx != NULL);
-       g_return_if_fail (auth != NULL);
-
-       server = ctx->server;
-
-       if (!server->valid_auths)
-               return;
-
-       uri = soup_context_get_uri (ctx);
-       if (g_hash_table_lookup_extended (server->valid_auths,
-                                         uri->path,
-                                         (gpointer *) &old_path,
-                                         (gpointer *) &old_auth)) {
-               g_hash_table_remove (server->valid_auths, old_path);
-               g_free (old_path);
-               soup_auth_free (old_auth);
-       }
-}
-
-void
-soup_auth_set_context (SoupAuth *auth, SoupContext *ctx)
-{
-       SoupHost *server;
-       SoupAuth *old_auth = NULL;
-       gchar *old_path;
-       const SoupUri *uri;
-
-       g_return_if_fail (ctx != NULL);
-       g_return_if_fail (auth != NULL);
-
-       server = ctx->server;
-       uri = soup_context_get_uri (ctx);
-
-       if (!server->valid_auths) {
-               server->valid_auths = g_hash_table_new (g_str_hash, 
-                                                       g_str_equal);
-       }
-       else if (g_hash_table_lookup_extended (server->valid_auths, 
-                                              uri->path,
-                                              (gpointer *) &old_path,
-                                              (gpointer *) &old_auth)) {
-               if (auth == old_auth)
-                       return;
-
-               g_hash_table_remove (server->valid_auths, old_path);
-               g_free (old_path);
-               soup_auth_free (old_auth);
-       }
-
-       g_hash_table_insert (server->valid_auths,
-                            g_strdup (uri->path),
-                            auth);
-}
-
 typedef SoupAuth *(*SoupAuthNewFn) (void);
 
 typedef struct {
@@ -662,7 +689,7 @@ typedef struct {
 
 static AuthScheme known_auth_schemes [] = {
        { "Basic",  soup_auth_new_basic,  0 },
-       { "NTLM",   ntlm_new,             2 },
+       { "NTLM",   soup_auth_new_ntlm,   2 },
        { "Digest", soup_auth_new_digest, 3 },
        { NULL }
 };
@@ -727,6 +754,14 @@ soup_auth_initialize (SoupAuth *auth, const SoupUri *uri)
        auth->init_func (auth, uri);
 }
 
+gboolean
+soup_auth_invalidate (SoupAuth *auth)
+{
+       g_return_val_if_fail (auth != NULL, FALSE);
+
+       return auth->invalidate_func (auth);
+}
+
 gchar *
 soup_auth_authorize (SoupAuth *auth, SoupMessage *msg)
 {
@@ -744,3 +779,22 @@ soup_auth_free (SoupAuth *auth)
        g_free (auth->realm);
        auth->free_func (auth);
 }
+
+GSList *
+soup_auth_get_protection_space (SoupAuth *auth, const SoupUri *source_uri)
+{
+       g_return_val_if_fail (auth != NULL, NULL);
+       g_return_val_if_fail (source_uri != NULL, NULL);
+
+       return auth->pspace_func (auth, source_uri);
+}
+
+void
+soup_auth_free_protection_space (SoupAuth *auth, GSList *space)
+{
+       GSList *s;
+
+       for (s = space; s; s = s->next)
+               g_free (s->data);
+       g_slist_free (space);
+}