Index: gtk/gtkprintbackend.c
===================================================================
--- gtk/gtkprintbackend.c	(revision 22399)
+++ gtk/gtkprintbackend.c	(working copy)
@@ -25,6 +25,7 @@
 
 #include "gtkintl.h"
 #include "gtkmodules.h"
+#include "gtkmarshalers.h"
 #include "gtkprivate.h"
 #include "gtkprintbackend.h"
 #include "gtkprinter-private.h"
@@ -49,6 +50,9 @@
   guint printer_list_requested : 1;
   guint printer_list_done : 1;
   GtkPrintBackendStatus status;
+  char *hostname;
+  char *username;
+  char *password;
 };
 
 enum {
@@ -57,6 +61,7 @@
   PRINTER_ADDED,
   PRINTER_REMOVED,
   PRINTER_STATUS_CHANGED,
+  REQUEST_PASSWORD,
   LAST_SIGNAL
 };
 
@@ -353,6 +358,13 @@
 static GList *              fallback_printer_list_papers           (GtkPrinter          *printer);
 static GtkPageSetup *       fallback_printer_get_default_page_size (GtkPrinter          *printer);
 static GtkPrintCapabilities fallback_printer_get_capabilities      (GtkPrinter          *printer);
+static void                 request_password                       (GtkPrintBackend     *backend,
+                                                                    const gchar         *hostname,
+                                                                    const gchar         *username);
+static void                 fallback_set_password                  (GtkPrintBackend     *backend,
+                                                                    const gchar         *hostname,
+                                                                    const gchar         *username,
+                                                                    const gchar         *password);
   
 static void
 gtk_print_backend_class_init (GtkPrintBackendClass *class)
@@ -372,6 +384,8 @@
   class->printer_list_papers = fallback_printer_list_papers;
   class->printer_get_default_page_size = fallback_printer_get_default_page_size;
   class->printer_get_capabilities = fallback_printer_get_capabilities;
+  class->request_password = request_password;
+  class->set_password = fallback_set_password;
   
   g_object_class_install_property (object_class, 
                                    PROP_STATUS,
@@ -425,6 +439,14 @@
 		  NULL, NULL,
 		  g_cclosure_marshal_VOID__OBJECT,
 		  G_TYPE_NONE, 1, GTK_TYPE_PRINTER);
+  signals[REQUEST_PASSWORD] =
+    g_signal_new (I_("request-password"),
+		  G_TYPE_FROM_CLASS (class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
+		  NULL, NULL,
+		  _gtk_marshal_VOID__STRING_STRING,
+		  G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
 }
 
 static void
@@ -437,6 +459,9 @@
   priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal, 
 					  (GDestroyNotify) g_free,
 					  (GDestroyNotify) g_object_unref);
+  priv->hostname = NULL;
+  priv->username = NULL;
+  priv->password = NULL;
 }
 
 static void
@@ -640,6 +665,116 @@
 						       dnotify);
 }
 
+void 
+gtk_print_backend_set_password (GtkPrintBackend *backend,
+                                const gchar     *hostname,
+                                const gchar     *username,
+                                const gchar     *password)
+{
+  g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
+
+  GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, hostname, username, password);
+}
+
+void 
+fallback_set_password (GtkPrintBackend *backend,
+                       const gchar     *hostname,
+                       const gchar     *username,
+                       const gchar     *password)
+{
+}
+
+static void
+store_password (GtkEntry        *entry,
+                GtkPrintBackend *backend)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+
+  if (priv->password != NULL)
+    {
+      memset (priv->password, 0, strlen (priv->password));
+      g_free (priv->password);
+    }
+
+  priv->password = g_strdup (gtk_entry_get_text (entry));
+}
+
+static void
+password_dialog_response (GtkWidget       *dialog,
+                          gint             response_id,
+                          GtkPrintBackend *backend)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+
+  if (response_id == GTK_RESPONSE_OK)
+    gtk_print_backend_set_password (backend, priv->hostname, priv->username, priv->password);
+  else
+    gtk_print_backend_set_password (backend, priv->hostname, priv->username, NULL);
+
+  if (priv->password != NULL)
+    {
+      memset (priv->password, 0, strlen (priv->password));
+      g_free (priv->password);
+      priv->password = NULL;
+    }
+
+  gtk_widget_destroy (dialog);
+
+  g_object_unref (backend);
+}
+
+static void
+request_password (GtkPrintBackend *backend,
+                  const gchar     *hostname,
+                  const gchar     *username)
+{
+  GtkPrintBackendPrivate *priv = backend->priv;
+  GtkWidget *dialog, *box, *label, *prompt, *entry;
+  gchar *text;
+
+  dialog = gtk_dialog_new_with_buttons (_("Password"), NULL, GTK_DIALOG_MODAL, 
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_OK, GTK_RESPONSE_OK,
+                                        NULL);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+  box = gtk_hbox_new (FALSE, 0); 
+
+ /* Translators: the first string is a username and the second is a hostname of a CUPS server
+  *              against which the user is being authenticated.
+  */
+  text = g_strdup_printf ( _("Please enter the password for %s on %s"), username, hostname);
+
+  label = gtk_label_new (text);
+  gtk_misc_set_padding (GTK_MISC (label), 12, 0);
+  g_free (text);
+
+  prompt = gtk_label_new (_("Password:"));
+
+  entry = gtk_entry_new ();
+  gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
+  gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+
+  g_signal_connect (entry, "changed",
+                    G_CALLBACK (store_password), backend);
+
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label, FALSE, FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), box, FALSE, FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (box), prompt, FALSE, FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 12);
+
+  priv->hostname = g_strdup (hostname);
+  priv->username = g_strdup (username);
+  g_object_ref (backend);
+  g_signal_connect (G_OBJECT (dialog), "response",
+                    G_CALLBACK (password_dialog_response), backend);
+
+  gtk_widget_show_all (dialog);
+  gtk_widget_show (dialog);
+}
+
 void
 gtk_print_backend_destroy (GtkPrintBackend *print_backend)
 {
Index: gtk/gtkprintbackend.h
===================================================================
--- gtk/gtkprintbackend.h	(revision 22399)
+++ gtk/gtkprintbackend.h	(working copy)
@@ -120,14 +120,21 @@
 							      GtkPrinter          *printer);
   void                  (*printer_status_changed)            (GtkPrintBackend     *backend,
 							      GtkPrinter          *printer);
+  void                  (*request_password)                  (GtkPrintBackend     *backend,
+                                                              const gchar         *hostname,
+                                                              const gchar         *username);
 
+  /* not a signal */
+  void                  (*set_password)                      (GtkPrintBackend     *backend,
+                                                              const gchar         *hostname,
+                                                              const gchar         *username,
+                                                              const gchar         *password);
+
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
   void (*_gtk_reserved3) (void);
   void (*_gtk_reserved4) (void);
-  void (*_gtk_reserved5) (void);
-  void (*_gtk_reserved6) (void);
 };
 
 GType   gtk_print_backend_get_type       (void) G_GNUC_CONST;
@@ -144,6 +151,10 @@
 						    GDestroyNotify           dnotify);
 GList *     gtk_print_backend_load_modules         (void);
 void        gtk_print_backend_destroy              (GtkPrintBackend         *print_backend);
+void        gtk_print_backend_set_password         (GtkPrintBackend         *backend, 
+                                                    const gchar             *hostname,
+                                                    const gchar             *username,
+                                                    const gchar             *password);
 
 /* Backend-only functions for GtkPrintBackend */
 
Index: gtk/gtkprintunixdialog.c
===================================================================
--- gtk/gtkprintunixdialog.c	(revision 22399)
+++ gtk/gtkprintunixdialog.c	(working copy)
@@ -757,7 +757,10 @@
     priv->print_backends = gtk_print_backend_load_modules ();
 
   for (node = priv->print_backends; node != NULL; node = node->next)
-    printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
+    {
+      GtkPrintBackend *backend = node->data;
+      printer_list_initialize (dialog, backend);
+    }
 }
 
 static void
Index: modules/printbackends/cups/gtkcupsutils.c
===================================================================
--- modules/printbackends/cups/gtkcupsutils.c	(revision 22399)
+++ modules/printbackends/cups/gtkcupsutils.c	(working copy)
@@ -39,10 +39,12 @@
 static void _post_write_request (GtkCupsRequest *request);
 static void _post_write_data    (GtkCupsRequest *request);
 static void _post_check         (GtkCupsRequest *request);
+static void _post_auth          (GtkCupsRequest *request);
 static void _post_read_response (GtkCupsRequest *request);
 
 static void _get_send           (GtkCupsRequest *request);
 static void _get_check          (GtkCupsRequest *request);
+static void _get_auth           (GtkCupsRequest *request);
 static void _get_read_data      (GtkCupsRequest *request);
 
 struct _GtkCupsResult
@@ -69,6 +71,7 @@
   _post_write_request,
   _post_write_data,
   _post_check,
+  _post_auth,
   _post_read_response
 };
 
@@ -76,6 +79,7 @@
   _connect,
   _get_send,
   _get_check,
+  _get_auth,
   _get_read_data
 };
 
@@ -123,6 +127,8 @@
   request->type = req_type;
   request->state = GTK_CUPS_REQUEST_START;
 
+  request->password_state = GTK_CUPS_PASSWORD_NONE;
+
    if (server)
     request->server = g_strdup (server);
   else
@@ -205,6 +211,11 @@
 
   g_free (request->server);
   g_free (request->resource);
+  if (request->password != NULL)
+    {
+      memset (request->password, 0, strlen (request->password));
+      g_free (request->password);
+    }
 
   gtk_cups_result_free (request->result);
 
@@ -786,12 +797,79 @@
           return;
         }
     }
-   else
+  else if (http_status == HTTP_UNAUTHORIZED)
     {
+      request->state = GTK_CUPS_POST_CHECK;
+      request->poll_state = GTK_CUPS_HTTP_READ;
+
+      request->attempts = 0;
+      return;
+    }
+  else
+    {
       request->attempts++;
     }
 }
 
+static void
+_post_auth (GtkCupsRequest *request)
+{
+  if (request->password_state == GTK_CUPS_PASSWORD_HAS)
+    {
+      if (request->password == NULL)
+        {
+          request->state = GTK_CUPS_POST_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+          gtk_cups_result_set_error (request->result, 
+                                     GTK_CUPS_ERROR_AUTH,
+                                     0,
+                                     1,
+                                     "Canceled by user");
+        }
+      else
+        request->state = GTK_CUPS_POST_CHECK;
+    }
+}
+
+static void
+_get_auth (GtkCupsRequest *request)
+{
+  if (request->password_state == GTK_CUPS_PASSWORD_HAS)
+    {
+      if (request->password == NULL)
+        {
+          request->state = GTK_CUPS_GET_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+          gtk_cups_result_set_error (request->result, 
+                                     GTK_CUPS_ERROR_AUTH,
+                                     0,
+                                     1,
+                                     "Canceled by user");
+        }
+      else
+        request->state = GTK_CUPS_GET_CHECK;
+    }
+}
+
+/* Very ugly hack: cups has a stupid synchronous password callback 
+ * that doesn't even take the request or user data parameters, so 
+ * we have to use a static variable to pass the password to it.
+ * Not threadsafe !
+ * The callback sets cups_password to NULL to signal that the 
+ * password has been used.
+ */
+static char *cups_password;
+
+static const char *
+passwordCB (const char *prompt)
+{
+  char *pwd = cups_password;
+  cups_password = NULL;
+  return pwd;
+}
+
 static void 
 _post_check (GtkCupsRequest *request)
 {
@@ -810,18 +888,82 @@
     }
   else if (http_status == HTTP_UNAUTHORIZED)
     {
-      /* TODO: callout for auth */
-      g_warning ("NOT IMPLEMENTED: We need to prompt for authorization");
-      request->state = GTK_CUPS_POST_DONE;
-      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      int auth_result = -1;
+      httpFlush (request->http);
+
+      if (request->password_state == GTK_CUPS_PASSWORD_APPLIED)
+        {
+          request->password_state = GTK_CUPS_PASSWORD_NOT_VALID;
+          request->state = GTK_CUPS_POST_AUTH;
+          request->need_password = TRUE;
+
+          return;
+        }
+
+      /* Negotiate */
+      if (strncmp (httpGetField (request->http, HTTP_FIELD_WWW_AUTHENTICATE), "Negotiate", 9) == 0)
+        {
+          auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
+        }
+      /* Basic, BasicDigest, Digest and PeerCred */
+      else
+        {
+          if (request->password_state == GTK_CUPS_PASSWORD_NONE)
+            {
+              cups_password = g_strdup("");
+              cupsSetPasswordCB (passwordCB);
+
+              /* This call success for PeerCred authentication */
+              auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
+
+              if (auth_result != 0)
+                {
+                  /* move to AUTH state to let the backend 
+                   * ask for a password
+                   */ 
+                  request->state = GTK_CUPS_POST_AUTH;
+                  request->need_password = TRUE;
+
+                  return;
+                }
+            }
+          else
+            {
+              cups_password = request->password;
+
+              auth_result = cupsDoAuthentication (request->http, "POST", request->resource);
+
+              if (cups_password != NULL)
+                return;
+
+              request->password_state = GTK_CUPS_PASSWORD_APPLIED;
+            }
+        }
+
+      if (auth_result ||
+          httpReconnect (request->http))
+        {
+          /* if the password has been used, reset password_state
+           * so that we ask for a new one next time around
+           */ 
+          if (cups_password == NULL)
+            request->password_state = GTK_CUPS_PASSWORD_NONE;
+
+          request->state = GTK_CUPS_POST_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+          gtk_cups_result_set_error (request->result, 
+                                     GTK_CUPS_ERROR_AUTH,
+                                     0,
+                                     0,
+                                     "Not authorized");
+          return;
+        }
       
-      /* TODO: create a not implemented error code */
-      gtk_cups_result_set_error (request->result, 
-                                 GTK_CUPS_ERROR_GENERAL,
-                                 0,
-                                 0,
-                                 "Can't prompt for authorization");
-      return;
+      if (request->data_io != NULL)
+        g_io_channel_seek_position (request->data_io, 0, G_SEEK_SET, NULL);
+
+      request->state = GTK_CUPS_POST_CONNECT;
+      request->poll_state = GTK_CUPS_HTTP_WRITE;
     }
   else if (http_status == HTTP_ERROR)
     {
@@ -883,7 +1025,7 @@
                                      http_errno, 
                                      "HTTP Error in POST %s", 
                                      g_strerror (http_errno));
-         request->poll_state = GTK_CUPS_HTTP_IDLE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
  
           httpFlush (request->http); 
           return;
@@ -975,9 +1117,13 @@
     }
 
   httpClearFields (request->http);
+#ifdef HAVE_HTTPGETAUTHSTRING
+  httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString (request->http));
+#else
 #ifdef HAVE_HTTP_AUTHSTRING
   httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
 #endif
+#endif
 
   if (httpGet (request->http, request->resource))
     {
@@ -997,6 +1143,9 @@
       request->attempts++;
       return;    
     }
+
+  if (httpCheck (request->http))
+    request->last_status = httpUpdate (request->http);
         
   request->attempts = 0;
 
@@ -1024,18 +1173,81 @@
     }
   else if (http_status == HTTP_UNAUTHORIZED)
     {
-      /* TODO: callout for auth */
-      g_warning ("NOT IMPLEMENTED: We need to prompt for authorization in a non blocking manner");
-      request->state = GTK_CUPS_GET_DONE;
-      request->poll_state = GTK_CUPS_HTTP_IDLE;
+      int auth_result = -1;
+      httpFlush (request->http);
 
-      /* TODO: should add a status or error code for not implemented */ 
-      gtk_cups_result_set_error (request->result, 
-                                 GTK_CUPS_ERROR_GENERAL,
-                                 0,
-                                 0,
-                                 "Can't prompt for authorization");
-      return;
+      if (request->password_state == GTK_CUPS_PASSWORD_APPLIED)
+        {
+          request->password_state = GTK_CUPS_PASSWORD_NOT_VALID;
+          request->state = GTK_CUPS_GET_AUTH;
+          request->need_password = TRUE;
+
+          return;
+        }
+
+      /* Negotiate */
+      if (strncmp (httpGetField (request->http, HTTP_FIELD_WWW_AUTHENTICATE), "Negotiate", 9) == 0)
+        {
+          auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
+        }
+      /* Basic, BasicDigest, Digest and PeerCred */
+      else
+        {          
+          if (request->password_state == GTK_CUPS_PASSWORD_NONE)
+            {
+              cups_password = g_strdup("");
+              cupsSetPasswordCB (passwordCB);
+
+              /* This call success for PeerCred authentication */
+              auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
+
+              if (auth_result != 0)
+                {
+                  /* move to AUTH state to let the backend 
+                   * ask for a password
+                   */ 
+                  request->state = GTK_CUPS_GET_AUTH;
+                  request->need_password = TRUE;
+
+                  return;
+                }
+            }
+          else
+            {
+              cups_password = request->password;
+
+              auth_result = cupsDoAuthentication (request->http, "GET", request->resource);
+
+              if (cups_password != NULL)
+                return;
+
+              request->password_state = GTK_CUPS_PASSWORD_APPLIED;
+            }
+        }
+
+      if (auth_result ||
+          httpReconnect (request->http))
+        {
+          /* if the password has been used, reset password_state
+           * so that we ask for a new one next time around
+           */
+          if (cups_password == NULL)
+            request->password_state = GTK_CUPS_PASSWORD_NONE;
+
+          request->state = GTK_CUPS_GET_DONE;
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+          gtk_cups_result_set_error (request->result, 
+                                     GTK_CUPS_ERROR_AUTH,
+                                     0,
+                                     0,
+                                     "Not authorized");
+          return;
+        }
+
+      request->state = GTK_CUPS_GET_SEND;
+      request->last_status = HTTP_CONTINUE;
+
+     return;
     }
   else if (http_status == HTTP_UPGRADE_REQUIRED)
     {
@@ -1043,7 +1255,7 @@
       httpFlush (request->http);
 
       cupsSetEncryption (HTTP_ENCRYPT_REQUIRED);
-      request->state = GTK_CUPS_POST_CONNECT;
+      request->state = GTK_CUPS_GET_CONNECT;
 
       /* Reconnect... */
       httpReconnect (request->http);
@@ -1143,7 +1355,7 @@
 
   if (io_status == G_IO_STATUS_ERROR)
     {
-      request->state = GTK_CUPS_POST_DONE;
+      request->state = GTK_CUPS_GET_DONE;
       request->poll_state = GTK_CUPS_HTTP_IDLE;
     
       gtk_cups_result_set_error (request->result,
Index: modules/printbackends/cups/gtkprintbackendcups.c
===================================================================
--- modules/printbackends/cups/gtkprintbackendcups.c	(revision 22399)
+++ modules/printbackends/cups/gtkprintbackendcups.c	(working copy)
@@ -118,6 +118,10 @@
   char  *default_cover_before;
   char  *default_cover_after;
   int    number_of_covers;
+
+  GList *requests;
+  GHashTable *auth;
+  gboolean authentication_lock;
 };
 
 static GObjectClass *backend_parent_class;
@@ -176,7 +180,13 @@
 								    gdouble                            height,
 								    GIOChannel                        *cache_io);
 
+static void                 gtk_print_backend_cups_set_password    (GtkPrintBackend *backend, 
+                                                                    const gchar     *hostname,
+                                                                    const gchar     *username,
+                                                                    const gchar     *password);
 
+void                        overwrite_and_free                      (gpointer data);
+
 static void
 gtk_print_backend_cups_register_type (GTypeModule *module)
 {
@@ -271,6 +281,7 @@
   backend_class->printer_get_default_page_size = cups_printer_get_default_page_size;
   backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
   backend_class->printer_get_capabilities = cups_printer_get_capabilities;
+  backend_class->set_password = gtk_print_backend_cups_set_password;
 }
 
 static cairo_status_t
@@ -561,7 +572,17 @@
                         (GDestroyNotify)cups_free_print_stream_data);
 }
 
+void overwrite_and_free (gpointer data)
+{
+  gchar *password = (gchar *) data;
 
+  if (password != NULL)
+    {
+      memset (password, 0, strlen (password));
+      g_free (password);
+    }
+}
+
 static void
 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
 {
@@ -569,6 +590,10 @@
   backend_cups->got_default_printer = FALSE;  
   backend_cups->list_printers_pending = FALSE;
 
+  backend_cups->requests = NULL;
+  backend_cups->auth = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, overwrite_and_free);
+  backend_cups->authentication_lock = FALSE;
+
   backend_cups->covers = NULL;
   backend_cups->default_cover_before = NULL;
   backend_cups->default_cover_after = NULL;
@@ -602,6 +627,8 @@
   gtk_cups_connection_test_free (backend_cups->cups_connection_test);
   backend_cups->cups_connection_test = NULL;
 
+  g_hash_table_destroy (backend_cups->auth);
+
   backend_parent_class->finalize (object);
 }
 
@@ -626,8 +653,93 @@
   backend_parent_class->dispose (object);
 }
 
+static void
+gtk_print_backend_cups_set_password (GtkPrintBackend *backend,
+                                     const gchar     *hostname,
+                                     const gchar     *username, 
+                                     const gchar     *password)
+{
+  GtkPrintBackendCups *cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
+  GList *l;
+  char   dispatch_hostname[HTTP_MAX_URI];
+  gchar *key;
+  
+  key = g_strconcat (username, "@", hostname, NULL);
+  g_hash_table_insert (cups_backend->auth, key, g_strdup (password));
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS backend: storing password for %s\n", key));
+
+  for (l = cups_backend->requests; l; l = l->next)
+    {
+      GtkPrintCupsDispatchWatch *dispatch = l->data;
+      
+      httpGetHostname (dispatch->request->http, dispatch_hostname, sizeof (dispatch_hostname));
+      if (dispatch_hostname[0] == '/' ||
+          strcmp (dispatch_hostname, "127.0.0.1") == 0 ||
+          strcmp (dispatch_hostname, "[::1]") == 0)
+        strcpy (dispatch_hostname, "localhost");
+
+      if (strcmp (hostname, dispatch_hostname) == 0) 
+        {
+          overwrite_and_free (dispatch->request->password);
+          dispatch->request->password = g_strdup (password);
+          dispatch->request->password_state = GTK_CUPS_PASSWORD_HAS;
+          dispatch->backend->authentication_lock = FALSE;
+        }
+    }
+}
+
 static gboolean
+request_password (gpointer data)
+{
+  char hostname[HTTP_MAX_URI];
+  const gchar *username;
+  gchar *password;
+  gchar *key;
+  GtkPrintCupsDispatchWatch *dispatch = data;
+
+  if (dispatch->backend->authentication_lock)
+    return FALSE;
+
+  httpGetHostname (dispatch->request->http, hostname, sizeof (hostname));
+  if (hostname[0] == '/' ||
+      strcmp (hostname, "127.0.0.1") == 0 ||
+      strcmp (hostname, "[::1]") == 0)
+    strcpy (hostname, "localhost");
+
+  username = cupsUser ();
+  key = g_strconcat (username, "@", hostname, NULL);
+  password = g_hash_table_lookup (dispatch->backend->auth, key);
+
+  if (password && dispatch->request->password_state != GTK_CUPS_PASSWORD_NOT_VALID)
+    {
+      GTK_NOTE (PRINTING,
+                g_print ("CUPS backend: using stored password for %s\n", key));
+
+      overwrite_and_free (dispatch->request->password);
+      dispatch->request->password = g_strdup (password);
+      dispatch->request->password_state = GTK_CUPS_PASSWORD_HAS;
+    }
+  else
+    {
+      if (dispatch->request->password_state == GTK_CUPS_PASSWORD_NOT_VALID)
+        g_hash_table_remove (dispatch->backend->auth, key);
+
+      dispatch->request->password_state = GTK_CUPS_PASSWORD_REQUESTED;
+
+      dispatch->backend->authentication_lock = TRUE;
+      g_signal_emit_by_name (dispatch->backend, "request-password", 
+                             hostname, username);
+    }
+
+  
+  g_free (key);
+
+  return FALSE;
+}
+
+static gboolean
 cups_dispatch_watch_check (GSource *source)
 {
   GtkPrintCupsDispatchWatch *dispatch;
@@ -665,7 +777,7 @@
 #endif
     }
     
-  if (poll_state != GTK_CUPS_HTTP_IDLE)  
+  if (poll_state != GTK_CUPS_HTTP_IDLE && !dispatch->request->need_password)
     if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) 
        return FALSE;
   
@@ -676,6 +788,13 @@
       g_free (dispatch->data_poll);
       dispatch->data_poll = NULL;
     }
+
+  if (dispatch->request->need_password && dispatch->request->password_state != GTK_CUPS_PASSWORD_REQUESTED)
+    {
+      dispatch->request->need_password = FALSE;
+      g_idle_add (request_password, dispatch);
+      result = FALSE;
+    }
   
   return result;
 }
@@ -735,12 +854,38 @@
 cups_dispatch_watch_finalize (GSource *source)
 {
   GtkPrintCupsDispatchWatch *dispatch;
+  GtkCupsResult *result;
 
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
 
   dispatch = (GtkPrintCupsDispatchWatch *) source;
 
+  result = gtk_cups_request_get_result (dispatch->request);
+  if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH)
+    {
+      const gchar *username;
+      gchar        hostname[HTTP_MAX_URI];
+      gchar       *key;
+    
+      httpGetHostname (dispatch->request->http, hostname, sizeof (hostname));
+      if (hostname[0] == '/' ||
+          strcmp (hostname, "127.0.0.1") == 0 ||
+          strcmp (hostname, "[::1]") == 0)
+        strcpy (hostname, "localhost");
+
+      username = cupsUser ();
+
+      key = g_strconcat (username, "@", hostname, NULL);
+      GTK_NOTE (PRINTING,
+                g_print ("CUPS backend: removing stored password for %s\n", key));
+      g_hash_table_remove (dispatch->backend->auth, key);
+      g_free (key);
+      
+      if (dispatch->backend)
+        dispatch->backend->authentication_lock = FALSE;
+    }
+
   gtk_cups_request_free (dispatch->request);
 
   if (dispatch->backend)
@@ -754,6 +899,10 @@
        * of print backends. See _gtk_print_backend_create for the
        * disabling.
        */
+
+      dispatch->backend->requests = g_list_remove (dispatch->backend->requests, dispatch);
+
+      
       g_object_unref (dispatch->backend);
       dispatch->backend = NULL;
     }
@@ -788,6 +937,8 @@
   dispatch->backend = g_object_ref (print_backend);
   dispatch->data_poll = NULL;
 
+  print_backend->requests = g_list_prepend (print_backend->requests, dispatch);
+
   g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
 
   g_source_attach ((GSource *) dispatch, NULL);
@@ -1121,9 +1272,20 @@
   if (gtk_cups_result_is_error (result))
     {
       GTK_NOTE (PRINTING, 
-                g_warning ("CUPS Backend: Error getting printer list: %s", 
-        	           gtk_cups_result_get_error_string (result)));
+                g_warning ("CUPS Backend: Error getting printer list: %s %d %d", 
+                           gtk_cups_result_get_error_string (result),
+                           gtk_cups_result_get_error_type (result),
+                           gtk_cups_result_get_error_code (result)));
 
+      if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH &&
+          gtk_cups_result_get_error_code (result) == 1)
+        {
+          /* Canceled by user, stop popping up more password dialogs */
+          if (cups_backend->list_printers_poll > 0)
+            g_source_remove (cups_backend->list_printers_poll);
+          cups_backend->list_printers_poll = 0;
+        }
+
       goto done;
     }
   
@@ -1786,8 +1948,6 @@
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
 
-  g_free (resource);
-  g_free (ppd_filename);
 
   cups_printer->reading_ppd = TRUE;
 
@@ -1798,6 +1958,9 @@
                         (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
                         data,
                         (GDestroyNotify)get_ppd_data_free);
+
+  g_free (resource);
+  g_free (ppd_filename);
 }
 
 /* Ordering matters for default preference */
@@ -2018,6 +2181,20 @@
 
   GDK_THREADS_ENTER ();
 
+  if (gtk_cups_result_is_error (result))
+    {
+      if (gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_AUTH &&
+          gtk_cups_result_get_error_code (result) == 1)
+        {
+          /* Canceled by user, stop popping up more password dialogs */
+          if (print_backend->list_printers_poll > 0)
+            g_source_remove (print_backend->list_printers_poll);
+          print_backend->list_printers_poll = 0;
+        }
+
+      return;
+    }
+
   response = gtk_cups_result_get_response (result);
   
   if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
Index: modules/printbackends/cups/gtkcupsutils.h
===================================================================
--- modules/printbackends/cups/gtkcupsutils.h	(revision 22399)
+++ modules/printbackends/cups/gtkcupsutils.h	(working copy)
@@ -37,6 +37,7 @@
   GTK_CUPS_ERROR_HTTP,
   GTK_CUPS_ERROR_IPP,
   GTK_CUPS_ERROR_IO,
+  GTK_CUPS_ERROR_AUTH,
   GTK_CUPS_ERROR_GENERAL
 } GtkCupsErrorType;
 
@@ -66,6 +67,15 @@
   GTK_CUPS_CONNECTION_IN_PROGRESS  
 } GtkCupsConnectionState;
 
+typedef enum
+{
+  GTK_CUPS_PASSWORD_NONE,
+  GTK_CUPS_PASSWORD_REQUESTED,
+  GTK_CUPS_PASSWORD_HAS,
+  GTK_CUPS_PASSWORD_APPLIED,
+  GTK_CUPS_PASSWORD_NOT_VALID
+} GtkCupsPasswordState;
+
 struct _GtkCupsRequest 
 {
   GtkCupsRequestType type;
@@ -84,7 +94,11 @@
   gint state;
   GtkCupsPollState poll_state;
 
-  gint own_http : 1; 
+  gchar *password;
+
+  gint own_http : 1;
+  gint need_password : 1;
+  GtkCupsPasswordState password_state;
 };
 
 struct _GtkCupsConnectionTest
@@ -108,6 +122,7 @@
   GTK_CUPS_POST_WRITE_REQUEST,
   GTK_CUPS_POST_WRITE_DATA,
   GTK_CUPS_POST_CHECK,
+  GTK_CUPS_POST_AUTH,
   GTK_CUPS_POST_READ_RESPONSE,
   GTK_CUPS_POST_DONE = GTK_CUPS_REQUEST_DONE
 };
@@ -118,6 +133,7 @@
   GTK_CUPS_GET_CONNECT = GTK_CUPS_REQUEST_START,
   GTK_CUPS_GET_SEND,
   GTK_CUPS_GET_CHECK,
+  GTK_CUPS_GET_AUTH,
   GTK_CUPS_GET_READ_DATA,
   GTK_CUPS_GET_DONE = GTK_CUPS_REQUEST_DONE
 };
