Blah. Cvs sucks.
authorAlex Graveley <orph@src.gnome.org>
Tue, 12 Mar 2002 00:47:31 +0000 (00:47 +0000)
committerAlex Graveley <orph@src.gnome.org>
Tue, 12 Mar 2002 00:47:31 +0000 (00:47 +0000)
libsoup/soup-method.c [new file with mode: 0644]
libsoup/soup-method.h [new file with mode: 0644]
libsoup/soup-server-auth.c [new file with mode: 0644]
libsoup/soup-server-auth.h [new file with mode: 0644]

diff --git a/libsoup/soup-method.c b/libsoup/soup-method.c
new file mode 100644 (file)
index 0000000..a6d0332
--- /dev/null
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-method.c: HTTP Method related processing.
+ *
+ * Authors:
+ *      Alex Graveley (alex@ximian.com)
+ *
+ * Copyright (C) 2001, Ximian, Inc.
+ */
+
+#include <glib.h>
+
+#include "soup-method.h"
+
+SoupMethodId
+soup_method_get_id (const gchar *method)
+{
+       g_return_val_if_fail (method != NULL, SOUP_METHOD_ID_UNKNOWN);
+
+       switch (*method) {
+        case 'H':
+               if (g_strcasecmp (method, "HEAD") == 0)
+                       return SOUP_METHOD_ID_HEAD;
+               break;
+        case 'G':
+               if (g_strcasecmp (method, "GET") == 0)
+                       return SOUP_METHOD_ID_GET;
+               break;
+        case 'P':
+               if (g_strcasecmp (method, "POST") == 0)
+                       return SOUP_METHOD_ID_POST;
+               if (g_strcasecmp (method, "PUT") == 0)
+                       return SOUP_METHOD_ID_PUT;
+               if (g_strcasecmp (method, "PATCH") == 0)
+                       return SOUP_METHOD_ID_PATCH;
+               if (g_strcasecmp (method, "PROPFIND") == 0)
+                       return SOUP_METHOD_ID_PROPFIND;
+               if (g_strcasecmp (method, "PROPPATCH") == 0)
+                       return SOUP_METHOD_ID_PROPPATCH;
+               break;
+        case 'D':
+               if (g_strcasecmp (method, "DELETE") == 0)
+                       return SOUP_METHOD_ID_DELETE;
+               break;
+        case 'C':
+               if (g_strcasecmp (method, "CONNECT") == 0)
+                       return SOUP_METHOD_ID_CONNECT;
+               if (g_strcasecmp (method, "COPY") == 0)
+                       return SOUP_METHOD_ID_COPY;
+               break;
+        case 'M':
+               if (g_strcasecmp (method, "MKCOL") == 0)
+                       return SOUP_METHOD_ID_MKCOL;
+               if (g_strcasecmp (method, "MOVE") == 0)
+                       return SOUP_METHOD_ID_MOVE;
+               break;
+        case 'O':
+               if (g_strcasecmp (method, "OPTIONS") == 0)
+                       return SOUP_METHOD_ID_OPTIONS;
+               break;
+        case 'T':
+               if (g_strcasecmp (method, "TRACE") == 0)
+                       return SOUP_METHOD_ID_TRACE;
+               break;
+        case 'L':
+               if (g_strcasecmp (method, "LOCK") == 0)
+                       return SOUP_METHOD_ID_LOCK;
+               break;
+        case 'U':
+               if (g_strcasecmp (method, "UNLOCK") == 0)
+                       return SOUP_METHOD_ID_UNLOCK;
+               break;
+       }
+
+       return SOUP_METHOD_ID_UNKNOWN;
+}
+
diff --git a/libsoup/soup-method.h b/libsoup/soup-method.h
new file mode 100644 (file)
index 0000000..99c0f08
--- /dev/null
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-method.h: HTTP Method defines and related processing.
+ *
+ * Authors:
+ *      Alex Graveley (alex@ximian.com)
+ *
+ * Copyright (C) 2001, Ximian, Inc.
+ */
+
+#ifndef SOUP_METHOD_H
+#define SOUP_METHOD_H 1
+
+#define SOUP_METHOD_POST      "POST"
+#define SOUP_METHOD_GET       "GET"
+#define SOUP_METHOD_HEAD      "HEAD"
+#define SOUP_METHOD_OPTIONS   "OPTIONS"
+#define SOUP_METHOD_PUT       "PUT"
+#define SOUP_METHOD_MOVE      "MOVE"
+#define SOUP_METHOD_COPY      "COPY"
+#define SOUP_METHOD_DELETE    "DELETE"
+#define SOUP_METHOD_TRACE     "TRACE"
+#define SOUP_METHOD_CONNECT   "CONNECT"
+#define SOUP_METHOD_MKCOL     "MKCOL"
+#define SOUP_METHOD_PROPPATCH "PROPPATCH"
+#define SOUP_METHOD_PROPFIND  "PROPFIND"
+#define SOUP_METHOD_PATCH     "PATCH"
+#define SOUP_METHOD_LOCK      "LOCK"
+#define SOUP_METHOD_UNLOCK    "UNLOCK"
+
+typedef enum {
+       SOUP_METHOD_ID_UNKNOWN = 0,
+       SOUP_METHOD_ID_POST,
+       SOUP_METHOD_ID_GET,
+       SOUP_METHOD_ID_HEAD,
+       SOUP_METHOD_ID_OPTIONS,
+       SOUP_METHOD_ID_PUT,
+       SOUP_METHOD_ID_MOVE,
+       SOUP_METHOD_ID_COPY,
+       SOUP_METHOD_ID_DELETE,
+       SOUP_METHOD_ID_TRACE,
+       SOUP_METHOD_ID_CONNECT,
+       SOUP_METHOD_ID_MKCOL,
+       SOUP_METHOD_ID_PROPPATCH,
+       SOUP_METHOD_ID_PROPFIND,
+       SOUP_METHOD_ID_PATCH,
+       SOUP_METHOD_ID_LOCK,
+       SOUP_METHOD_ID_UNLOCK
+} SoupMethodId;
+
+SoupMethodId soup_method_get_id (const char *method);
+
+#endif /* SOUP_METHOD_H */
diff --git a/libsoup/soup-server-auth.c b/libsoup/soup-server-auth.c
new file mode 100644 (file)
index 0000000..f579a97
--- /dev/null
@@ -0,0 +1,511 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-server-auth.c: Server-side authentication handling
+ *
+ * Authors:
+ *      Alex Graveley (alex@ximian.com)
+ *
+ * Copyright (C) 2001, Ximian, Inc.
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "soup-server-auth.h"
+
+#include "md5-utils.h"
+#include "soup-headers.h"
+#include "soup-ntlm.h"
+
+typedef struct {
+       const gchar   *scheme;
+       SoupAuthType   type;
+       gint           strength;
+} AuthScheme; 
+
+static AuthScheme known_auth_schemes [] = {
+       { "Basic",  SOUP_AUTH_TYPE_BASIC,  0 },
+       { "NTLM",   SOUP_AUTH_TYPE_NTLM,   2 },
+       { "Digest", SOUP_AUTH_TYPE_DIGEST, 3 },
+       { NULL }
+};
+
+static SoupAuthType
+soup_auth_get_strongest_header (guint          auth_types,
+                               const GSList  *vals, 
+                               gchar        **out_hdr)
+{
+       gchar *header = NULL;
+       AuthScheme *scheme = NULL, *iter;
+
+       g_return_val_if_fail (vals != NULL, 0);
+
+       if (!auth_types) 
+               return 0;
+
+       while (vals) {
+               for (iter = known_auth_schemes; iter->scheme; iter++) {
+                       gchar *tryheader = vals->data;
+
+                       if ((iter->type & auth_types) &&
+                           !g_strncasecmp (tryheader, 
+                                           iter->scheme, 
+                                           strlen (iter->scheme))) {
+                               if (!scheme || 
+                                   scheme->strength < iter->strength) {
+                                       header = tryheader;
+                                       scheme = iter;
+                               }
+                               break;
+                       }
+               }
+
+               vals = vals->next;
+       }
+
+       if (!scheme) 
+               return 0;
+
+       *out_hdr = header + strlen (scheme->scheme) + 1;
+       return scheme->type;
+}
+
+static void
+digest_hex (guchar *digest, guchar hex[33])
+{
+       guchar *s, *p;
+
+       /* lowercase hexify that bad-boy... */
+       for (s = digest, p = hex; p < hex + 32; s++, p += 2)
+               sprintf (p, "%.2x", *s);
+}
+
+static gboolean 
+check_digest_passwd (SoupServerAuthDigest *digest,
+                    gchar                *passwd)
+{
+       MD5Context ctx;
+       guchar d[16];
+       guchar hex_a1 [33], hex_a2[33], o[33];
+       gchar *tmp;
+
+       /* compute A1 */
+       md5_init (&ctx);
+       md5_update (&ctx, digest->user, strlen (digest->user));
+       md5_update (&ctx, ":", 1);
+       md5_update (&ctx, digest->realm, strlen (digest->realm));
+       md5_update (&ctx, ":", 1);
+
+       if (passwd)
+               md5_update (&ctx, passwd, strlen (passwd));
+
+       if (digest->algorithm == SOUP_ALGORITHM_MD5_SESS) {
+               md5_final (&ctx, d);
+
+               md5_init (&ctx);
+               md5_update (&ctx, d, 16);
+               md5_update (&ctx, ":", 1);
+               md5_update (&ctx, digest->nonce, strlen (digest->nonce));
+               md5_update (&ctx, ":", 1);
+               md5_update (&ctx, digest->cnonce, strlen (digest->cnonce));
+       }
+
+       /* hexify A1 */
+       md5_final (&ctx, d);
+       digest_hex (d, hex_a1);
+
+       /* compute A2 */
+       md5_init (&ctx);
+       md5_update (&ctx, 
+                   digest->request_method, 
+                   strlen (digest->request_method));
+       md5_update (&ctx, ":", 1);
+       md5_update (&ctx, digest->digest_uri, strlen (digest->digest_uri));
+
+       if (digest->integrity) {
+               /* FIXME: Actually implement. Ugh. */
+               md5_update (&ctx, ":", 1);
+               md5_update (&ctx, "00000000000000000000000000000000", 32);
+       }
+
+       /* hexify A2 */
+       md5_final (&ctx, d);
+       digest_hex (d, hex_a2);
+
+       /* compute KD */
+       md5_init (&ctx);
+       md5_update (&ctx, hex_a1, 32);
+       md5_update (&ctx, ":", 1);
+       md5_update (&ctx, digest->nonce, strlen (digest->nonce));
+       md5_update (&ctx, ":", 1);
+
+       tmp = g_strdup_printf ("%.8x", digest->nonce_count);
+       md5_update (&ctx, tmp, strlen (tmp));
+       g_free (tmp);
+
+       md5_update (&ctx, ":", 1);
+       md5_update (&ctx, digest->cnonce, strlen (digest->cnonce));
+       md5_update (&ctx, ":", 1);
+
+       if (digest->integrity)
+               tmp = "auth-int";
+       else 
+               tmp = "auth";
+
+       md5_update (&ctx, tmp, strlen (tmp));
+       md5_update (&ctx, ":", 1);
+
+       md5_update (&ctx, hex_a2, 32);
+       md5_final (&ctx, d);
+
+       digest_hex (d, o);
+
+       return strcmp (o, digest->digest_response) == 0;
+}
+
+gboolean 
+soup_server_auth_check_passwd (SoupServerAuth *auth,
+                              gchar          *passwd)
+{
+       g_return_val_if_fail (auth != NULL, TRUE);
+
+       switch (auth->type) {
+       case SOUP_AUTH_TYPE_BASIC:
+               if (passwd && auth->basic.passwd)
+                       return strcmp (auth->basic.passwd, passwd) == 0;
+               else
+                       return passwd == auth->basic.passwd;
+       case SOUP_AUTH_TYPE_DIGEST:
+               return check_digest_passwd (&auth->digest, passwd);
+       case SOUP_AUTH_TYPE_NTLM:
+               if (passwd) {
+                       gchar lm_hash [21], nt_hash [21];
+
+                       soup_ntlm_lanmanager_hash (passwd, lm_hash);
+                       soup_ntlm_nt_hash (passwd, nt_hash);
+
+                       if (memcmp (lm_hash, 
+                                   auth->ntlm.lm_hash, 
+                                   sizeof (lm_hash)) != 0)
+                               return FALSE;
+
+                       if (memcmp (nt_hash, 
+                                   auth->ntlm.nt_hash, 
+                                   sizeof (nt_hash)) != 0)
+                               return FALSE;
+
+                       return TRUE;
+               }
+               return FALSE;
+       }
+
+       return FALSE;
+}
+
+const gchar *
+soup_server_auth_get_user (SoupServerAuth *auth)
+{
+       g_return_val_if_fail (auth != NULL, NULL);
+
+       switch (auth->type) {
+       case SOUP_AUTH_TYPE_BASIC:
+               return auth->basic.user;
+       case SOUP_AUTH_TYPE_DIGEST:
+               return auth->digest.user;
+       case SOUP_AUTH_TYPE_NTLM:
+               return auth->ntlm.user;
+       }
+
+       return NULL;
+}
+
+static gboolean
+parse_digest (SoupServerAuthContext *auth_ctx, 
+             gchar                 *header,
+             SoupMessage           *msg,
+             SoupServerAuth        *out_auth)
+{
+       GHashTable *tokens;
+       gchar *user, *realm, *uri, *response;
+       gchar *nonce, *cnonce;
+       gint nonce_count;
+       gboolean integrity;
+
+       user = realm = uri = response = NULL;
+       nonce = cnonce = NULL;
+       nonce_count = 0;
+       integrity = FALSE;
+
+       tokens = soup_header_param_parse_list (header);
+       if (!tokens) 
+               goto DIGEST_AUTH_FAIL;
+
+       /* Check uri */
+       {
+               SoupUri *dig_uri;
+               const SoupUri *req_uri;
+
+               uri = soup_header_param_copy_token (tokens, "uri");
+               if (!uri)
+                       goto DIGEST_AUTH_FAIL;
+
+               req_uri = soup_context_get_uri (msg->context);
+
+               dig_uri = soup_uri_new (uri);
+               if (dig_uri) {
+                       if (!soup_uri_equal (dig_uri, req_uri)) {
+                               soup_uri_free (dig_uri);
+                               goto DIGEST_AUTH_FAIL;
+                       }
+                       soup_uri_free (dig_uri);
+               } else {        
+                       gchar *req_path;
+
+                       if (req_uri->querystring)
+                               req_path = 
+                                       g_strdup_printf ("%s?%s", 
+                                                        req_uri->path, 
+                                                        req_uri->querystring);
+                       else
+                               req_path = g_strdup (req_uri->path);
+
+                       if (strcmp (uri, req_path) != 0) {
+                               g_free (req_path);
+                               goto DIGEST_AUTH_FAIL;
+                       }
+                       g_free (req_path);
+               }
+       }
+
+       /* Check qop */
+       {
+               gchar *qop;
+               qop = soup_header_param_copy_token (tokens, "qop");
+               if (!qop)
+                       goto DIGEST_AUTH_FAIL;
+
+               if (!strcmp (qop, "auth-int")) {
+                       g_free (qop);
+                       integrity = TRUE;
+               } else if (auth_ctx->digest_info.force_integrity) {
+                       g_free (qop);
+                       goto DIGEST_AUTH_FAIL;
+               }
+       }                       
+
+       /* Check realm */
+       realm = soup_header_param_copy_token (tokens, "realm");
+       if (!realm && auth_ctx->digest_info.realm)
+               goto DIGEST_AUTH_FAIL;
+       else if (realm && 
+                auth_ctx->digest_info.realm &&
+                strcmp (realm, auth_ctx->digest_info.realm) != 0)
+               goto DIGEST_AUTH_FAIL;
+
+       /* Check username */
+       user = soup_header_param_copy_token (tokens, "username");
+       if (!user)
+               goto DIGEST_AUTH_FAIL;
+
+       /* Check nonce */
+       nonce = soup_header_param_copy_token (tokens, "nonce");
+       if (!nonce)
+               goto DIGEST_AUTH_FAIL;
+
+       /* Check nonce count */
+       {
+               gchar *nc;
+               nc = soup_header_param_copy_token (tokens, "nc");
+               if (!nc)
+                       goto DIGEST_AUTH_FAIL;
+
+               nonce_count = atoi (nc);
+               if (nonce_count <= 0) {
+                       g_free (nc);
+                       goto DIGEST_AUTH_FAIL;
+               }
+               g_free (nc);
+       }
+
+       cnonce = soup_header_param_copy_token (tokens, "cnonce");
+       if (!cnonce)
+               goto DIGEST_AUTH_FAIL;
+
+       response = soup_header_param_copy_token (tokens, "response");
+       if (!response)
+               goto DIGEST_AUTH_FAIL;
+
+       out_auth->digest.type            = SOUP_AUTH_TYPE_DIGEST;
+       out_auth->digest.digest_uri      = uri;
+       out_auth->digest.integrity       = integrity;
+       out_auth->digest.realm           = realm;
+       out_auth->digest.user            = user;
+       out_auth->digest.nonce           = nonce;
+       out_auth->digest.nonce_count     = nonce_count;
+       out_auth->digest.cnonce          = cnonce;
+       out_auth->digest.digest_response = response;
+       out_auth->digest.request_method  = msg->method;
+
+       soup_header_param_destroy_hash (tokens);
+
+       return TRUE;
+
+ DIGEST_AUTH_FAIL:
+       if (tokens)
+               soup_header_param_destroy_hash (tokens);
+
+       g_free (user);
+       g_free (realm);
+       g_free (nonce);
+       g_free (response);
+       g_free (cnonce);
+       g_free (uri);
+
+       return FALSE;
+}
+
+SoupServerAuth * 
+soup_server_auth_new (SoupServerAuthContext *auth_ctx, 
+                     const GSList          *auth_hdrs, 
+                     SoupMessage           *msg)
+{
+       SoupServerAuth *ret;
+       SoupAuthType type;
+       gchar *header = NULL;
+
+       g_return_val_if_fail (auth_ctx != NULL, NULL);
+       g_return_val_if_fail (msg != NULL, NULL);
+
+       if (!auth_hdrs && auth_ctx->types) {
+               soup_message_set_error (msg, SOUP_ERROR_UNAUTHORIZED);
+               return NULL;
+       }
+
+       type = soup_auth_get_strongest_header (auth_ctx->types,
+                                              auth_hdrs, 
+                                              &header);
+
+       if (!type && auth_ctx->types) {
+               soup_message_set_error (msg, SOUP_ERROR_UNAUTHORIZED);
+               return NULL;
+       }
+
+       ret = g_new0 (SoupServerAuth, 1);
+
+       switch (type) {
+       case SOUP_AUTH_TYPE_BASIC:
+               {
+                       gchar *userpass, *colon;
+                       gint len;
+
+                       userpass = soup_base64_decode (header, &len);
+                       if (!userpass)
+                               break;
+
+                       colon = strchr (userpass, ':');
+                       if (!colon) {
+                               g_free (userpass);
+                               break;
+                       }
+
+                       ret->basic.type = SOUP_AUTH_TYPE_BASIC;
+                       ret->basic.user = g_strndup (userpass, 
+                                                    colon - userpass);
+                       ret->basic.passwd = g_strdup (colon + 1);
+
+                       g_free (userpass);
+
+                       return ret;
+               }
+       case SOUP_AUTH_TYPE_DIGEST:
+               if (parse_digest (auth_ctx, header, msg, ret))
+                       return ret;
+               break;
+       case SOUP_AUTH_TYPE_NTLM:
+               g_warning ("NTLM server authentication not yet implemented\n");
+               break;
+       }
+
+       g_free (ret);
+
+       soup_message_set_error (msg, SOUP_ERROR_UNAUTHORIZED);
+       return NULL;
+}
+
+void
+soup_server_auth_free (SoupServerAuth *auth)
+{
+       g_return_if_fail (auth != NULL);
+
+       switch (auth->type) {
+       case SOUP_AUTH_TYPE_BASIC:
+               g_free ((gchar *) auth->basic.user);
+               g_free ((gchar *) auth->basic.passwd);
+               break;
+       case SOUP_AUTH_TYPE_DIGEST:
+               g_free ((gchar *) auth->digest.realm);
+               g_free ((gchar *) auth->digest.user);
+               g_free ((gchar *) auth->digest.nonce);
+               g_free ((gchar *) auth->digest.cnonce);
+               g_free ((gchar *) auth->digest.digest_uri);
+               g_free ((gchar *) auth->digest.digest_response);
+               break;
+       case SOUP_AUTH_TYPE_NTLM:
+               g_free ((gchar *) auth->ntlm.host);
+               g_free ((gchar *) auth->ntlm.domain);
+               g_free ((gchar *) auth->ntlm.user);
+               g_free ((gchar *) auth->ntlm.lm_hash);
+               g_free ((gchar *) auth->ntlm.nt_hash);
+               break;
+       }
+
+       g_free (auth);
+}
+
+void
+soup_server_auth_context_challenge (SoupServerAuthContext *auth_ctx,
+                                   SoupMessage           *msg,
+                                   gchar                 *header_name)
+{
+       if (auth_ctx->types & SOUP_AUTH_TYPE_BASIC) {
+               gchar *hdr;
+
+               hdr = g_strdup_printf ("Basic realm=\"%s\"", 
+                                      auth_ctx->basic_info.realm);
+               soup_message_add_header (msg->response_headers,
+                                        header_name,
+                                        hdr);
+               g_free (hdr);
+       }
+
+       if (auth_ctx->types & SOUP_AUTH_TYPE_DIGEST) {
+               GString *str;
+
+               str = g_string_new ("Digest ");
+
+               if (auth_ctx->digest_info.realm)
+                       g_string_sprintfa (str, 
+                                          "realm=\"%s\", ", 
+                                          auth_ctx->digest_info.realm);
+
+               g_string_sprintfa (str, 
+                                  "nonce=\"%lu%lu\", ", 
+                                  (unsigned long) msg,
+                                  (unsigned long) time (0));
+
+               if (auth_ctx->digest_info.force_integrity) 
+                       g_string_sprintfa (str, "qop=\"auth-int\", ");
+               else
+                       g_string_sprintfa (str, "qop=\"auth,auth-int\", ");
+
+               g_string_sprintfa (str, "algorithm=\"MD5,MD5-sess\"");
+
+               soup_message_add_header (msg->response_headers,
+                                        header_name,
+                                        str->str);
+               g_string_free (str, TRUE);
+       }
+}
diff --git a/libsoup/soup-server-auth.h b/libsoup/soup-server-auth.h
new file mode 100644 (file)
index 0000000..c623cc1
--- /dev/null
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-server-auth.h: Server-side authentication handling
+ *
+ * Authors:
+ *      Alex Graveley (alex@ximian.com)
+ *
+ * Copyright (C) 2001, Ximian, Inc.
+ */
+
+#ifndef SOUP_SERVER_AUTH_H
+#define SOUP_SERVER_AUTH_H 1
+
+#include <glib.h>
+#include <libsoup/soup-message.h>
+#include <libsoup/soup-misc.h>
+
+typedef union _SoupServerAuth SoupServerAuth;
+typedef struct _SoupServerAuthContext SoupServerAuthContext;
+
+typedef gboolean (*SoupServerAuthCallbackFn) (SoupServerAuthContext *auth_ctx,
+                                             SoupServerAuth        *auth,
+                                             SoupMessage           *msg, 
+                                             gpointer               data);
+
+struct _SoupServerAuthContext {
+       guint                     types;
+       SoupServerAuthCallbackFn  callback;
+       gpointer                  user_data;
+
+       struct {
+               const gchar *realm;
+       } basic_info;
+
+       struct {
+               const gchar *realm;
+               guint        allow_algorithms;
+               gboolean     force_integrity;
+       } digest_info;
+};
+
+void soup_server_auth_context_challenge (SoupServerAuthContext *auth_ctx,
+                                        SoupMessage           *msg,
+                                        gchar                 *header_name);
+
+
+typedef struct {
+       SoupAuthType  type;
+       const gchar  *user;
+       const gchar  *passwd;
+} SoupServerAuthBasic;
+
+typedef enum {
+       SOUP_ALGORITHM_MD5      = 1 << 0,
+       SOUP_ALGORITHM_MD5_SESS = 1 << 1
+} SoupDigestAlgorithm;
+
+typedef struct {
+       SoupAuthType          type;
+       SoupDigestAlgorithm   algorithm;
+       gboolean              integrity;
+       const gchar          *realm;
+       const gchar          *user;
+       const gchar          *nonce;
+       gint                  nonce_count;
+       const gchar          *cnonce;
+       const gchar          *digest_uri;
+       const gchar          *digest_response;
+       const gchar          *request_method;
+} SoupServerAuthDigest;
+
+typedef struct {
+       SoupAuthType  type;
+       const gchar  *host;
+       const gchar  *domain;
+       const gchar  *user;
+       const gchar  *lm_hash;
+       const gchar  *nt_hash;
+} SoupServerAuthNTLM;
+
+union _SoupServerAuth {
+       SoupAuthType          type;
+       SoupServerAuthBasic   basic;
+       SoupServerAuthDigest  digest;
+       SoupServerAuthNTLM    ntlm;
+};
+
+SoupServerAuth *soup_server_auth_new          (SoupServerAuthContext *auth_ctx, 
+                                              const GSList          *auth_hdrs,
+                                              SoupMessage           *msg);
+
+void            soup_server_auth_free         (SoupServerAuth        *auth);
+
+const gchar    *soup_server_auth_get_user     (SoupServerAuth        *auth);
+
+gboolean        soup_server_auth_check_passwd (SoupServerAuth        *auth,
+                                              gchar                 *passwd);
+
+#endif /* SOUP_SERVER_AUTH_H */