(root)/
glib-2.79.0/
gio/
gdbusauth.c
       1  /* GDBus - GLib D-Bus Library
       2   *
       3   * Copyright (C) 2008-2010 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: David Zeuthen <davidz@redhat.com>
      21   */
      22  
      23  #include "config.h"
      24  
      25  #include "gdbusauth.h"
      26  
      27  #include "gdbusauthmechanismanon.h"
      28  #include "gdbusauthmechanismexternal.h"
      29  #include "gdbusauthmechanismsha1.h"
      30  #include "gdbusauthobserver.h"
      31  
      32  #include "gdbuserror.h"
      33  #include "gdbusutils.h"
      34  #include "gioenumtypes.h"
      35  #include "gcredentials.h"
      36  #include "gcredentialsprivate.h"
      37  #include "gdbusprivate.h"
      38  #include "giostream.h"
      39  #include "gdatainputstream.h"
      40  #include "gdataoutputstream.h"
      41  
      42  #include "gnetworking.h"
      43  #include "gunixconnection.h"
      44  #include "gunixcredentialsmessage.h"
      45  
      46  #include "glibintl.h"
      47  
      48  G_GNUC_PRINTF(1, 2)
      49  static void
      50  debug_print (const gchar *message, ...)
      51  {
      52    if (G_UNLIKELY (_g_dbus_debug_authentication ()))
      53      {
      54        gchar *s;
      55        GString *str;
      56        va_list var_args;
      57        guint n;
      58  
      59        _g_dbus_debug_print_lock ();
      60  
      61        va_start (var_args, message);
      62        s = g_strdup_vprintf (message, var_args);
      63        va_end (var_args);
      64  
      65        str = g_string_new (NULL);
      66        for (n = 0; s[n] != '\0'; n++)
      67          {
      68            if (G_UNLIKELY (s[n] == '\r'))
      69              g_string_append (str, "\\r");
      70            else if (G_UNLIKELY (s[n] == '\n'))
      71              g_string_append (str, "\\n");
      72            else
      73              g_string_append_c (str, s[n]);
      74          }
      75        g_print ("GDBus-debug:Auth: %s\n", str->str);
      76        g_string_free (str, TRUE);
      77        g_free (s);
      78  
      79        _g_dbus_debug_print_unlock ();
      80      }
      81  }
      82  
      83  typedef struct
      84  {
      85    const gchar *name;
      86    gint priority;
      87    GType gtype;
      88  } Mechanism;
      89  
      90  static void mechanism_free (Mechanism *m);
      91  
      92  struct _GDBusAuthPrivate
      93  {
      94    GIOStream *stream;
      95  
      96    /* A list of available Mechanism, sorted according to priority  */
      97    GList *available_mechanisms;
      98  };
      99  
     100  enum
     101  {
     102    PROP_0,
     103    PROP_STREAM
     104  };
     105  
     106  G_DEFINE_TYPE_WITH_PRIVATE (GDBusAuth, _g_dbus_auth, G_TYPE_OBJECT)
     107  
     108  /* ---------------------------------------------------------------------------------------------------- */
     109  
     110  static void
     111  _g_dbus_auth_finalize (GObject *object)
     112  {
     113    GDBusAuth *auth = G_DBUS_AUTH (object);
     114  
     115    if (auth->priv->stream != NULL)
     116      g_object_unref (auth->priv->stream);
     117    g_list_free_full (auth->priv->available_mechanisms, (GDestroyNotify) mechanism_free);
     118  
     119    if (G_OBJECT_CLASS (_g_dbus_auth_parent_class)->finalize != NULL)
     120      G_OBJECT_CLASS (_g_dbus_auth_parent_class)->finalize (object);
     121  }
     122  
     123  static void
     124  _g_dbus_auth_get_property (GObject    *object,
     125                             guint       prop_id,
     126                             GValue     *value,
     127                             GParamSpec *pspec)
     128  {
     129    GDBusAuth *auth = G_DBUS_AUTH (object);
     130  
     131    switch (prop_id)
     132      {
     133      case PROP_STREAM:
     134        g_value_set_object (value, auth->priv->stream);
     135        break;
     136  
     137      default:
     138        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     139        break;
     140      }
     141  }
     142  
     143  static void
     144  _g_dbus_auth_set_property (GObject      *object,
     145                             guint         prop_id,
     146                             const GValue *value,
     147                             GParamSpec   *pspec)
     148  {
     149    GDBusAuth *auth = G_DBUS_AUTH (object);
     150  
     151    switch (prop_id)
     152      {
     153      case PROP_STREAM:
     154        auth->priv->stream = g_value_dup_object (value);
     155        break;
     156  
     157      default:
     158        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     159        break;
     160      }
     161  }
     162  
     163  static void
     164  _g_dbus_auth_class_init (GDBusAuthClass *klass)
     165  {
     166    GObjectClass *gobject_class;
     167  
     168    gobject_class = G_OBJECT_CLASS (klass);
     169    gobject_class->get_property = _g_dbus_auth_get_property;
     170    gobject_class->set_property = _g_dbus_auth_set_property;
     171    gobject_class->finalize     = _g_dbus_auth_finalize;
     172  
     173    g_object_class_install_property (gobject_class,
     174                                     PROP_STREAM,
     175                                     g_param_spec_object ("stream", NULL, NULL,
     176                                                          G_TYPE_IO_STREAM,
     177                                                          G_PARAM_READABLE |
     178                                                          G_PARAM_WRITABLE |
     179                                                          G_PARAM_CONSTRUCT_ONLY |
     180                                                          G_PARAM_STATIC_NAME |
     181                                                          G_PARAM_STATIC_BLURB |
     182                                                          G_PARAM_STATIC_NICK));
     183  }
     184  
     185  static void
     186  mechanism_free (Mechanism *m)
     187  {
     188    g_free (m);
     189  }
     190  
     191  static void
     192  add_mechanism (GDBusAuth         *auth,
     193                 GDBusAuthObserver *observer,
     194                 GType              mechanism_type)
     195  {
     196    const gchar *name;
     197  
     198    name = _g_dbus_auth_mechanism_get_name (mechanism_type);
     199    if (observer == NULL || g_dbus_auth_observer_allow_mechanism (observer, name))
     200      {
     201        Mechanism *m;
     202        m = g_new0 (Mechanism, 1);
     203        m->name = name;
     204        m->priority = _g_dbus_auth_mechanism_get_priority (mechanism_type);
     205        m->gtype = mechanism_type;
     206        auth->priv->available_mechanisms = g_list_prepend (auth->priv->available_mechanisms, m);
     207      }
     208  }
     209  
     210  static gint
     211  mech_compare_func (Mechanism *a, Mechanism *b)
     212  {
     213    gint ret;
     214    /* ensure deterministic order */
     215    ret = b->priority - a->priority;
     216    if (ret == 0)
     217      ret = g_strcmp0 (b->name, a->name);
     218    return ret;
     219  }
     220  
     221  static void
     222  _g_dbus_auth_init (GDBusAuth *auth)
     223  {
     224    auth->priv = _g_dbus_auth_get_instance_private (auth);
     225  }
     226  
     227  static void
     228  _g_dbus_auth_add_mechs (GDBusAuth         *auth,
     229                          GDBusAuthObserver *observer)
     230  {
     231    /* TODO: trawl extension points */
     232    add_mechanism (auth, observer, G_TYPE_DBUS_AUTH_MECHANISM_ANON);
     233    add_mechanism (auth, observer, G_TYPE_DBUS_AUTH_MECHANISM_SHA1);
     234    add_mechanism (auth, observer, G_TYPE_DBUS_AUTH_MECHANISM_EXTERNAL);
     235  
     236    auth->priv->available_mechanisms = g_list_sort (auth->priv->available_mechanisms,
     237                                                    (GCompareFunc) mech_compare_func);
     238  }
     239  
     240  static GType
     241  find_mech_by_name (GDBusAuth *auth,
     242                     const gchar *name)
     243  {
     244    GType ret;
     245    GList *l;
     246  
     247    ret = (GType) 0;
     248  
     249    for (l = auth->priv->available_mechanisms; l != NULL; l = l->next)
     250      {
     251        Mechanism *m = l->data;
     252        if (g_strcmp0 (name, m->name) == 0)
     253          {
     254            ret = m->gtype;
     255            goto out;
     256          }
     257      }
     258  
     259   out:
     260    return ret;
     261  }
     262  
     263  GDBusAuth  *
     264  _g_dbus_auth_new (GIOStream *stream)
     265  {
     266    return g_object_new (G_TYPE_DBUS_AUTH,
     267                         "stream", stream,
     268                         NULL);
     269  }
     270  
     271  /* ---------------------------------------------------------------------------------------------------- */
     272  /* like g_data_input_stream_read_line() but sets error if there's no content to read */
     273  static gchar *
     274  _my_g_data_input_stream_read_line (GDataInputStream  *dis,
     275                                     gsize             *out_line_length,
     276                                     GCancellable      *cancellable,
     277                                     GError           **error)
     278  {
     279    gchar *ret;
     280  
     281    g_return_val_if_fail (error == NULL || *error == NULL, NULL);
     282  
     283    ret = g_data_input_stream_read_line (dis,
     284                                         out_line_length,
     285                                         cancellable,
     286                                         error);
     287    if (ret == NULL && error != NULL && *error == NULL)
     288      {
     289        g_set_error_literal (error,
     290                             G_IO_ERROR,
     291                             G_IO_ERROR_FAILED,
     292                             _("Unexpected lack of content trying to read a line"));
     293      }
     294  
     295    return ret;
     296  }
     297  
     298  /* This function is to avoid situations like this
     299   *
     300   * BEGIN\r\nl\0\0\1...
     301   *
     302   * e.g. where we read into the first D-Bus message while waiting for
     303   * the final line from the client (TODO: file bug against gio for
     304   * this)
     305   */
     306  static gchar *
     307  _my_g_input_stream_read_line_safe (GInputStream  *i,
     308                                     gsize         *out_line_length,
     309                                     GCancellable  *cancellable,
     310                                     GError       **error)
     311  {
     312    GString *str;
     313    gchar c;
     314    gssize num_read;
     315    gboolean last_was_cr;
     316  
     317    str = g_string_new (NULL);
     318  
     319    last_was_cr = FALSE;
     320    while (TRUE)
     321      {
     322        num_read = g_input_stream_read (i,
     323                                        &c,
     324                                        1,
     325                                        cancellable,
     326                                        error);
     327        if (num_read == -1)
     328          goto fail;
     329        if (num_read == 0)
     330          {
     331            if (error != NULL && *error == NULL)
     332              {
     333                g_set_error_literal (error,
     334                                     G_IO_ERROR,
     335                                     G_IO_ERROR_FAILED,
     336                                     _("Unexpected lack of content trying to (safely) read a line"));
     337              }
     338            goto fail;
     339          }
     340  
     341        g_string_append_c (str, (gint) c);
     342        if (last_was_cr)
     343          {
     344            if (c == 0x0a)
     345              {
     346                g_assert (str->len >= 2);
     347                g_string_set_size (str, str->len - 2);
     348                goto out;
     349              }
     350          }
     351        last_was_cr = (c == 0x0d);
     352      }
     353  
     354   out:
     355    if (out_line_length != NULL)
     356      *out_line_length = str->len;
     357    return g_string_free (str, FALSE);
     358  
     359   fail:
     360    g_assert (error == NULL || *error != NULL);
     361    g_string_free (str, TRUE);
     362    return NULL;
     363  }
     364  
     365  /* ---------------------------------------------------------------------------------------------------- */
     366  
     367  static gchar *
     368  hexdecode (const gchar  *str,
     369             gsize        *out_len,
     370             GError      **error)
     371  {
     372    gchar *ret;
     373    GString *s;
     374    guint n;
     375  
     376    ret = NULL;
     377    s = g_string_new (NULL);
     378  
     379    for (n = 0; str[n] != '\0'; n += 2)
     380      {
     381        gint upper_nibble;
     382        gint lower_nibble;
     383        guint value;
     384  
     385        upper_nibble = g_ascii_xdigit_value (str[n]);
     386        lower_nibble = g_ascii_xdigit_value (str[n + 1]);
     387        if (upper_nibble == -1 || lower_nibble == -1)
     388          {
     389            g_set_error (error,
     390                         G_IO_ERROR,
     391                         G_IO_ERROR_FAILED,
     392                         "Error hexdecoding string '%s' around position %d",
     393                         str, n);
     394            goto out;
     395          }
     396        value = (upper_nibble<<4) | lower_nibble;
     397        g_string_append_c (s, value);
     398      }
     399  
     400    *out_len = s->len;
     401    ret = g_string_free (s, FALSE);
     402    s = NULL;
     403  
     404   out:
     405    if (s != NULL)
     406      {
     407        *out_len = 0;
     408        g_string_free (s, TRUE);
     409      }
     410     return ret;
     411  }
     412  
     413  /* ---------------------------------------------------------------------------------------------------- */
     414  
     415  static GDBusAuthMechanism *
     416  client_choose_mech_and_send_initial_response (GDBusAuth           *auth,
     417                                                GCredentials        *credentials_that_were_sent,
     418                                                GDBusConnectionFlags conn_flags,
     419                                                const gchar* const  *supported_auth_mechs,
     420                                                GPtrArray           *attempted_auth_mechs,
     421                                                GDataOutputStream   *dos,
     422                                                GCancellable        *cancellable,
     423                                                GError             **error)
     424  {
     425    GDBusAuthMechanism *mech;
     426    GType auth_mech_to_use_gtype;
     427    guint n;
     428    guint m;
     429    gchar *initial_response;
     430    gsize initial_response_len;
     431    gchar *encoded;
     432    gchar *s;
     433  
     434   again:
     435    mech = NULL;
     436  
     437    debug_print ("CLIENT: Trying to choose mechanism");
     438  
     439    /* find an authentication mechanism to try, if any */
     440    auth_mech_to_use_gtype = (GType) 0;
     441    for (n = 0; supported_auth_mechs[n] != NULL; n++)
     442      {
     443        gboolean attempted_already;
     444        attempted_already = FALSE;
     445        for (m = 0; m < attempted_auth_mechs->len; m++)
     446          {
     447            if (g_strcmp0 (supported_auth_mechs[n], attempted_auth_mechs->pdata[m]) == 0)
     448              {
     449                attempted_already = TRUE;
     450                break;
     451              }
     452          }
     453        if (!attempted_already)
     454          {
     455            auth_mech_to_use_gtype = find_mech_by_name (auth, supported_auth_mechs[n]);
     456            if (auth_mech_to_use_gtype != (GType) 0)
     457              break;
     458          }
     459      }
     460  
     461    if (auth_mech_to_use_gtype == (GType) 0)
     462      {
     463        gchar *available;
     464        GString *tried_str;
     465  
     466        debug_print ("CLIENT: Exhausted all available mechanisms");
     467  
     468        available = g_strjoinv (", ", (gchar **) supported_auth_mechs);
     469  
     470        tried_str = g_string_new (NULL);
     471        for (n = 0; n < attempted_auth_mechs->len; n++)
     472          {
     473            if (n > 0)
     474              g_string_append (tried_str, ", ");
     475            g_string_append (tried_str, attempted_auth_mechs->pdata[n]);
     476          }
     477        g_set_error (error,
     478                     G_IO_ERROR,
     479                     G_IO_ERROR_FAILED,
     480                     _("Exhausted all available authentication mechanisms (tried: %s) (available: %s)"),
     481                     tried_str->str,
     482                     available);
     483        g_string_free (tried_str, TRUE);
     484        g_free (available);
     485        goto out;
     486      }
     487  
     488    /* OK, decided on a mechanism - let's do this thing */
     489    mech = g_object_new (auth_mech_to_use_gtype,
     490                         "stream", auth->priv->stream,
     491                         "credentials", credentials_that_were_sent,
     492                         NULL);
     493    debug_print ("CLIENT: Trying mechanism '%s'", _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype));
     494    g_ptr_array_add (attempted_auth_mechs, (gpointer) _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype));
     495  
     496    /* the auth mechanism may not be supported
     497     * (for example, EXTERNAL only works if credentials were exchanged)
     498     */
     499    if (!_g_dbus_auth_mechanism_is_supported (mech))
     500      {
     501        debug_print ("CLIENT: Mechanism '%s' says it is not supported", _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype));
     502        g_object_unref (mech);
     503        mech = NULL;
     504        goto again;
     505      }
     506  
     507    initial_response_len = 0;
     508    initial_response = _g_dbus_auth_mechanism_client_initiate (mech,
     509                                                               conn_flags,
     510                                                               &initial_response_len);
     511  #if 0
     512    g_printerr ("using auth mechanism with name '%s' of type '%s' with initial response '%s'\n",
     513                _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype),
     514                g_type_name (G_TYPE_FROM_INSTANCE (mech)),
     515                initial_response);
     516  #endif
     517    if (initial_response != NULL)
     518      {
     519        //g_printerr ("initial_response = '%s'\n", initial_response);
     520        encoded = _g_dbus_hexencode (initial_response, initial_response_len);
     521        s = g_strdup_printf ("AUTH %s %s\r\n",
     522                             _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype),
     523                             encoded);
     524        g_free (initial_response);
     525        g_free (encoded);
     526      }
     527    else
     528      {
     529        s = g_strdup_printf ("AUTH %s\r\n", _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype));
     530      }
     531    debug_print ("CLIENT: writing '%s'", s);
     532    if (!g_data_output_stream_put_string (dos, s, cancellable, error))
     533      {
     534        g_object_unref (mech);
     535        mech = NULL;
     536        g_free (s);
     537        goto out;
     538      }
     539    g_free (s);
     540  
     541   out:
     542    return mech;
     543  }
     544  
     545  
     546  /* ---------------------------------------------------------------------------------------------------- */
     547  
     548  typedef enum
     549  {
     550    CLIENT_STATE_WAITING_FOR_DATA,
     551    CLIENT_STATE_WAITING_FOR_OK,
     552    CLIENT_STATE_WAITING_FOR_REJECT,
     553    CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD
     554  } ClientState;
     555  
     556  gchar *
     557  _g_dbus_auth_run_client (GDBusAuth     *auth,
     558                           GDBusAuthObserver     *observer,
     559                           GDBusConnectionFlags conn_flags,
     560                           GDBusCapabilityFlags offered_capabilities,
     561                           GDBusCapabilityFlags *out_negotiated_capabilities,
     562                           GCancellable  *cancellable,
     563                           GError       **error)
     564  {
     565    gchar *s;
     566    GDataInputStream *dis;
     567    GDataOutputStream *dos;
     568    GCredentials *credentials;
     569    gchar *ret_guid;
     570    gchar *line;
     571    gsize line_length;
     572    gchar **supported_auth_mechs;
     573    GPtrArray *attempted_auth_mechs;
     574    GDBusAuthMechanism *mech;
     575    ClientState state;
     576    GDBusCapabilityFlags negotiated_capabilities;
     577  
     578    g_return_val_if_fail ((conn_flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT), NULL);
     579    g_return_val_if_fail (!(conn_flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER), NULL);
     580  
     581    debug_print ("CLIENT: initiating");
     582  
     583    _g_dbus_auth_add_mechs (auth, observer);
     584  
     585    ret_guid = NULL;
     586    supported_auth_mechs = NULL;
     587    attempted_auth_mechs = g_ptr_array_new ();
     588    mech = NULL;
     589    negotiated_capabilities = 0;
     590    credentials = NULL;
     591  
     592    dis = G_DATA_INPUT_STREAM (g_data_input_stream_new (g_io_stream_get_input_stream (auth->priv->stream)));
     593    dos = G_DATA_OUTPUT_STREAM (g_data_output_stream_new (g_io_stream_get_output_stream (auth->priv->stream)));
     594    g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (dis), FALSE);
     595    g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (dos), FALSE);
     596  
     597    g_data_input_stream_set_newline_type (dis, G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
     598  
     599  #ifdef G_OS_UNIX
     600    if (G_IS_UNIX_CONNECTION (auth->priv->stream))
     601      {
     602        credentials = g_credentials_new ();
     603        if (!g_unix_connection_send_credentials (G_UNIX_CONNECTION (auth->priv->stream),
     604                                                 cancellable,
     605                                                 error))
     606          goto out;
     607      }
     608    else
     609      {
     610        if (!g_data_output_stream_put_byte (dos, '\0', cancellable, error))
     611          goto out;
     612      }
     613  #else
     614    if (!g_data_output_stream_put_byte (dos, '\0', cancellable, error))
     615      goto out;
     616  #endif
     617  
     618    if (credentials != NULL)
     619      {
     620        if (G_UNLIKELY (_g_dbus_debug_authentication ()))
     621          {
     622            s = g_credentials_to_string (credentials);
     623            debug_print ("CLIENT: sent credentials '%s'", s);
     624            g_free (s);
     625          }
     626      }
     627    else
     628      {
     629        debug_print ("CLIENT: didn't send any credentials");
     630      }
     631  
     632    /* TODO: to reduce roundtrips, try to pick an auth mechanism to start with */
     633  
     634    /* Get list of supported authentication mechanisms */
     635    s = "AUTH\r\n";
     636    debug_print ("CLIENT: writing '%s'", s);
     637    if (!g_data_output_stream_put_string (dos, s, cancellable, error))
     638      goto out;
     639    state = CLIENT_STATE_WAITING_FOR_REJECT;
     640  
     641    while (TRUE)
     642      {
     643        switch (state)
     644          {
     645          case CLIENT_STATE_WAITING_FOR_REJECT:
     646            debug_print ("CLIENT: WaitingForReject");
     647            line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
     648            if (line == NULL)
     649              goto out;
     650            debug_print ("CLIENT: WaitingForReject, read '%s'", line);
     651  
     652          choose_mechanism:
     653            if (!g_str_has_prefix (line, "REJECTED "))
     654              {
     655                g_set_error (error,
     656                             G_IO_ERROR,
     657                             G_IO_ERROR_FAILED,
     658                             "In WaitingForReject: Expected 'REJECTED am1 am2 ... amN', got '%s'",
     659                             line);
     660                g_free (line);
     661                goto out;
     662              }
     663            if (supported_auth_mechs == NULL)
     664              {
     665                supported_auth_mechs = g_strsplit (line + sizeof ("REJECTED ") - 1, " ", 0);
     666  #if 0
     667                for (n = 0; supported_auth_mechs != NULL && supported_auth_mechs[n] != NULL; n++)
     668                  g_printerr ("supported_auth_mechs[%d] = '%s'\n", n, supported_auth_mechs[n]);
     669  #endif
     670              }
     671            g_free (line);
     672            mech = client_choose_mech_and_send_initial_response (auth,
     673                                                                 credentials,
     674                                                                 conn_flags,
     675                                                                 (const gchar* const *) supported_auth_mechs,
     676                                                                 attempted_auth_mechs,
     677                                                                 dos,
     678                                                                 cancellable,
     679                                                                 error);
     680            if (mech == NULL)
     681              goto out;
     682            if (_g_dbus_auth_mechanism_client_get_state (mech) == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA)
     683              state = CLIENT_STATE_WAITING_FOR_DATA;
     684            else
     685              state = CLIENT_STATE_WAITING_FOR_OK;
     686            break;
     687  
     688          case CLIENT_STATE_WAITING_FOR_OK:
     689            debug_print ("CLIENT: WaitingForOK");
     690            line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
     691            if (line == NULL)
     692              goto out;
     693            debug_print ("CLIENT: WaitingForOK, read '%s'", line);
     694            if (g_str_has_prefix (line, "OK "))
     695              {
     696                if (!g_dbus_is_guid (line + 3))
     697                  {
     698                    g_set_error (error,
     699                                 G_IO_ERROR,
     700                                 G_IO_ERROR_FAILED,
     701                                 "Invalid OK response '%s'",
     702                                 line);
     703                    g_free (line);
     704                    goto out;
     705                  }
     706                ret_guid = g_strdup (line + 3);
     707                g_free (line);
     708  
     709                if (offered_capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
     710                  {
     711                    s = "NEGOTIATE_UNIX_FD\r\n";
     712                    debug_print ("CLIENT: writing '%s'", s);
     713                    if (!g_data_output_stream_put_string (dos, s, cancellable, error))
     714                      goto out;
     715                    state = CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD;
     716                  }
     717                else
     718                  {
     719                    s = "BEGIN\r\n";
     720                    debug_print ("CLIENT: writing '%s'", s);
     721                    if (!g_data_output_stream_put_string (dos, s, cancellable, error))
     722                      goto out;
     723                    /* and we're done! */
     724                    goto out;
     725                  }
     726              }
     727            else if (g_str_has_prefix (line, "REJECTED "))
     728              {
     729                goto choose_mechanism;
     730              }
     731            else
     732              {
     733                /* TODO: handle other valid responses */
     734                g_set_error (error,
     735                             G_IO_ERROR,
     736                             G_IO_ERROR_FAILED,
     737                             "In WaitingForOk: unexpected response '%s'",
     738                             line);
     739                g_free (line);
     740                goto out;
     741              }
     742            break;
     743  
     744          case CLIENT_STATE_WAITING_FOR_AGREE_UNIX_FD:
     745            debug_print ("CLIENT: WaitingForAgreeUnixFD");
     746            line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
     747            if (line == NULL)
     748              goto out;
     749            debug_print ("CLIENT: WaitingForAgreeUnixFD, read='%s'", line);
     750            if (g_strcmp0 (line, "AGREE_UNIX_FD") == 0)
     751              {
     752                g_free (line);
     753                negotiated_capabilities |= G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
     754                s = "BEGIN\r\n";
     755                debug_print ("CLIENT: writing '%s'", s);
     756                if (!g_data_output_stream_put_string (dos, s, cancellable, error))
     757                  goto out;
     758                /* and we're done! */
     759                goto out;
     760              }
     761            else if (g_str_has_prefix (line, "ERROR") && (line[5] == 0 || g_ascii_isspace (line[5])))
     762              {
     763                //g_strstrip (line + 5); g_debug ("bah, no unix_fd: '%s'", line + 5);
     764                g_free (line);
     765                s = "BEGIN\r\n";
     766                debug_print ("CLIENT: writing '%s'", s);
     767                if (!g_data_output_stream_put_string (dos, s, cancellable, error))
     768                  goto out;
     769                /* and we're done! */
     770                goto out;
     771              }
     772            else
     773              {
     774                /* TODO: handle other valid responses */
     775                g_set_error (error,
     776                             G_IO_ERROR,
     777                             G_IO_ERROR_FAILED,
     778                             "In WaitingForAgreeUnixFd: unexpected response '%s'",
     779                             line);
     780                g_free (line);
     781                goto out;
     782              }
     783            break;
     784  
     785          case CLIENT_STATE_WAITING_FOR_DATA:
     786            debug_print ("CLIENT: WaitingForData");
     787            line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
     788            if (line == NULL)
     789              goto out;
     790            debug_print ("CLIENT: WaitingForData, read='%s'", line);
     791            if (g_str_equal (line, "DATA") || g_str_has_prefix (line, "DATA "))
     792              {
     793                gchar *encoded;
     794                gchar *decoded_data;
     795                gsize decoded_data_len = 0;
     796  
     797                encoded = g_strdup (line + 4);
     798                g_free (line);
     799                g_strstrip (encoded);
     800                decoded_data = hexdecode (encoded, &decoded_data_len, error);
     801                g_free (encoded);
     802                if (decoded_data == NULL)
     803                  {
     804                    g_prefix_error (error, "DATA response is malformed: ");
     805                    /* invalid encoding, disconnect! */
     806                    goto out;
     807                  }
     808                _g_dbus_auth_mechanism_client_data_receive (mech, decoded_data, decoded_data_len);
     809                g_free (decoded_data);
     810  
     811                if (_g_dbus_auth_mechanism_client_get_state (mech) == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND)
     812                  {
     813                    gchar *data;
     814                    gsize data_len;
     815  
     816                    data = _g_dbus_auth_mechanism_client_data_send (mech, &data_len);
     817  
     818                    if (data_len == 0)
     819                      {
     820                        s = g_strdup ("DATA\r\n");
     821                      }
     822                    else
     823                      {
     824                        gchar *encoded_data = _g_dbus_hexencode (data, data_len);
     825  
     826                        s = g_strdup_printf ("DATA %s\r\n", encoded_data);
     827                        g_free (encoded_data);
     828                      }
     829  
     830                    g_free (data);
     831                    debug_print ("CLIENT: writing '%s'", s);
     832                    if (!g_data_output_stream_put_string (dos, s, cancellable, error))
     833                      {
     834                        g_free (s);
     835                        goto out;
     836                      }
     837                    g_free (s);
     838                  }
     839                state = CLIENT_STATE_WAITING_FOR_OK;
     840              }
     841            else if (g_str_has_prefix (line, "REJECTED "))
     842              {
     843                /* could be the chosen authentication method just doesn't work. Try
     844                 * another one...
     845                 */
     846                goto choose_mechanism;
     847              }
     848            else
     849              {
     850                g_set_error (error,
     851                             G_IO_ERROR,
     852                             G_IO_ERROR_FAILED,
     853                             "In WaitingForData: unexpected response '%s'",
     854                             line);
     855                g_free (line);
     856                goto out;
     857              }
     858            break;
     859  
     860          default:
     861            g_assert_not_reached ();
     862            break;
     863          }
     864  
     865      }; /* main authentication client loop */
     866  
     867   out:
     868    if (mech != NULL)
     869      g_object_unref (mech);
     870    g_ptr_array_unref (attempted_auth_mechs);
     871    g_strfreev (supported_auth_mechs);
     872    g_object_unref (dis);
     873    g_object_unref (dos);
     874  
     875    /* ensure return value is NULL if error is set */
     876    if (error != NULL && *error != NULL)
     877      {
     878        g_free (ret_guid);
     879        ret_guid = NULL;
     880      }
     881  
     882    if (ret_guid != NULL)
     883      {
     884        if (out_negotiated_capabilities != NULL)
     885          *out_negotiated_capabilities = negotiated_capabilities;
     886      }
     887  
     888    if (credentials != NULL)
     889      g_object_unref (credentials);
     890  
     891    debug_print ("CLIENT: Done, authenticated=%d", ret_guid != NULL);
     892  
     893    return ret_guid;
     894  }
     895  
     896  /* ---------------------------------------------------------------------------------------------------- */
     897  
     898  static gchar *
     899  get_auth_mechanisms (GDBusAuth     *auth,
     900                       gboolean       allow_anonymous,
     901                       const gchar   *prefix,
     902                       const gchar   *suffix,
     903                       const gchar   *separator)
     904  {
     905    GList *l;
     906    GString *str;
     907    gboolean need_sep;
     908  
     909    str = g_string_new (prefix);
     910    need_sep = FALSE;
     911    for (l = auth->priv->available_mechanisms; l != NULL; l = l->next)
     912      {
     913        Mechanism *m = l->data;
     914  
     915        if (!allow_anonymous && g_strcmp0 (m->name, "ANONYMOUS") == 0)
     916          continue;
     917  
     918        if (need_sep)
     919          g_string_append (str, separator);
     920        g_string_append (str, m->name);
     921        need_sep = TRUE;
     922      }
     923  
     924    g_string_append (str, suffix);
     925    return g_string_free (str, FALSE);
     926  }
     927  
     928  
     929  typedef enum
     930  {
     931    SERVER_STATE_WAITING_FOR_AUTH,
     932    SERVER_STATE_WAITING_FOR_DATA,
     933    SERVER_STATE_WAITING_FOR_BEGIN
     934  } ServerState;
     935  
     936  gboolean
     937  _g_dbus_auth_run_server (GDBusAuth              *auth,
     938                           GDBusAuthObserver      *observer,
     939                           const gchar            *guid,
     940                           gboolean                allow_anonymous,
     941                           gboolean                require_same_user,
     942                           GDBusCapabilityFlags    offered_capabilities,
     943                           GDBusCapabilityFlags   *out_negotiated_capabilities,
     944                           GCredentials          **out_received_credentials,
     945                           GCancellable           *cancellable,
     946                           GError                **error)
     947  {
     948    gboolean ret;
     949    ServerState state;
     950    GDataOutputStream *dos;
     951    GError *local_error;
     952    gchar *line;
     953    gsize line_length;
     954    GDBusAuthMechanism *mech;
     955    gchar *s;
     956    GDBusCapabilityFlags negotiated_capabilities;
     957    GCredentials *credentials;
     958    GCredentials *own_credentials = NULL;
     959  
     960    debug_print ("SERVER: initiating");
     961  
     962    _g_dbus_auth_add_mechs (auth, observer);
     963  
     964    ret = FALSE;
     965    dos = NULL;
     966    mech = NULL;
     967    negotiated_capabilities = 0;
     968    credentials = NULL;
     969  
     970    if (!g_dbus_is_guid (guid))
     971      {
     972        g_set_error (error,
     973                     G_IO_ERROR,
     974                     G_IO_ERROR_FAILED,
     975                     "The given GUID '%s' is not valid",
     976                     guid);
     977        goto out;
     978      }
     979  
     980    /* We use an extremely slow (but reliable) line reader for input
     981     * instead of something buffered - this basically does a recvfrom()
     982     * system call per character
     983     *
     984     * (the problem with using GDataInputStream's read_line is that
     985     * because of buffering it might start reading into the first D-Bus
     986     * message that appears after "BEGIN\r\n"....)
     987     */
     988  
     989    dos = G_DATA_OUTPUT_STREAM (g_data_output_stream_new (g_io_stream_get_output_stream (auth->priv->stream)));
     990    g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (dos), FALSE);
     991  
     992    /* read the NUL-byte, possibly with credentials attached */
     993  #ifndef G_CREDENTIALS_PREFER_MESSAGE_PASSING
     994    if (G_IS_SOCKET_CONNECTION (auth->priv->stream))
     995      {
     996        GSocket *sock = g_socket_connection_get_socket (G_SOCKET_CONNECTION (auth->priv->stream));
     997  
     998        local_error = NULL;
     999        credentials = g_socket_get_credentials (sock, &local_error);
    1000  
    1001        if (credentials == NULL && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
    1002          {
    1003            g_propagate_error (error, local_error);
    1004            goto out;
    1005          }
    1006        else
    1007          {
    1008            /* Clear the error indicator, so we can retry with
    1009             * g_unix_connection_receive_credentials() if necessary */
    1010            g_clear_error (&local_error);
    1011          }
    1012      }
    1013  #endif
    1014  
    1015    if (credentials == NULL && G_IS_UNIX_CONNECTION (auth->priv->stream))
    1016      {
    1017        local_error = NULL;
    1018        credentials = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (auth->priv->stream),
    1019                                                             cancellable,
    1020                                                             &local_error);
    1021        if (credentials == NULL && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
    1022          {
    1023            g_propagate_error (error, local_error);
    1024            goto out;
    1025          }
    1026        g_clear_error (&local_error);
    1027      }
    1028    else
    1029      {
    1030        gchar c;
    1031        gssize num_read;
    1032  
    1033        local_error = NULL;
    1034        num_read = g_input_stream_read (g_io_stream_get_input_stream (auth->priv->stream),
    1035                                        &c, 1,
    1036                                        cancellable, &local_error);
    1037        if (num_read != 1 || local_error != NULL)
    1038          {
    1039            if (local_error == NULL)
    1040              g_set_error_literal (error,
    1041                                   G_IO_ERROR,
    1042                                   G_IO_ERROR_FAILED,
    1043                                   _ ("Unexpected lack of content trying to read a byte"));
    1044            else
    1045              g_propagate_error (error, local_error);
    1046            goto out;
    1047          }
    1048      }
    1049  
    1050    if (credentials != NULL)
    1051      {
    1052        if (G_UNLIKELY (_g_dbus_debug_authentication ()))
    1053          {
    1054            s = g_credentials_to_string (credentials);
    1055            debug_print ("SERVER: received credentials '%s'", s);
    1056            g_free (s);
    1057          }
    1058      }
    1059    else
    1060      {
    1061        debug_print ("SERVER: didn't receive any credentials");
    1062      }
    1063  
    1064    own_credentials = g_credentials_new ();
    1065  
    1066    state = SERVER_STATE_WAITING_FOR_AUTH;
    1067    while (TRUE)
    1068      {
    1069        switch (state)
    1070          {
    1071          case SERVER_STATE_WAITING_FOR_AUTH:
    1072            debug_print ("SERVER: WaitingForAuth");
    1073            line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
    1074                                                      &line_length,
    1075                                                      cancellable,
    1076                                                      error);
    1077            debug_print ("SERVER: WaitingForAuth, read '%s'", line);
    1078            if (line == NULL)
    1079              goto out;
    1080            if (g_strcmp0 (line, "AUTH") == 0)
    1081              {
    1082                s = get_auth_mechanisms (auth, allow_anonymous, "REJECTED ", "\r\n", " ");
    1083                debug_print ("SERVER: writing '%s'", s);
    1084                if (!g_data_output_stream_put_string (dos, s, cancellable, error))
    1085                  {
    1086                    g_free (s);
    1087                    g_free (line);
    1088                    goto out;
    1089                  }
    1090                g_free (s);
    1091                g_free (line);
    1092              }
    1093            else if (g_str_has_prefix (line, "AUTH "))
    1094              {
    1095                gchar **tokens;
    1096                const gchar *encoded;
    1097                const gchar *mech_name;
    1098                GType auth_mech_to_use_gtype;
    1099  
    1100                tokens = g_strsplit (line, " ", 0);
    1101  
    1102                switch (g_strv_length (tokens))
    1103                  {
    1104                  case 2:
    1105                    /* no initial response */
    1106                    mech_name = tokens[1];
    1107                    encoded = NULL;
    1108                    break;
    1109  
    1110                  case 3:
    1111                    /* initial response */
    1112                    mech_name = tokens[1];
    1113                    encoded = tokens[2];
    1114                    break;
    1115  
    1116                  default:
    1117                    g_set_error (error,
    1118                                 G_IO_ERROR,
    1119                                 G_IO_ERROR_FAILED,
    1120                                 "Unexpected line '%s' while in WaitingForAuth state",
    1121                                 line);
    1122                    g_strfreev (tokens);
    1123                    g_free (line);
    1124                    goto out;
    1125                  }
    1126  
    1127                g_free (line);
    1128  
    1129                /* TODO: record that the client has attempted to use this mechanism */
    1130                //g_debug ("client is trying '%s'", mech_name);
    1131  
    1132                auth_mech_to_use_gtype = find_mech_by_name (auth, mech_name);
    1133                if ((auth_mech_to_use_gtype == (GType) 0) ||
    1134                    (!allow_anonymous && g_strcmp0 (mech_name, "ANONYMOUS") == 0))
    1135                  {
    1136                    /* We don't support this auth mechanism */
    1137                    g_strfreev (tokens);
    1138                    s = get_auth_mechanisms (auth, allow_anonymous, "REJECTED ", "\r\n", " ");
    1139                    debug_print ("SERVER: writing '%s'", s);
    1140                    if (!g_data_output_stream_put_string (dos, s, cancellable, error))
    1141                      {
    1142                        g_free (s);
    1143                        goto out;
    1144                      }
    1145                    g_free (s);
    1146  
    1147                    /* stay in WAITING FOR AUTH */
    1148                    state = SERVER_STATE_WAITING_FOR_AUTH;
    1149                  }
    1150                else
    1151                  {
    1152                    gchar *initial_response;
    1153                    gsize initial_response_len;
    1154  
    1155                    g_clear_object (&mech);
    1156                    mech = g_object_new (auth_mech_to_use_gtype,
    1157                                         "stream", auth->priv->stream,
    1158                                         "credentials", credentials,
    1159                                         NULL);
    1160  
    1161                    initial_response = NULL;
    1162                    initial_response_len = 0;
    1163                    if (encoded != NULL)
    1164                      {
    1165                        initial_response = hexdecode (encoded, &initial_response_len, error);
    1166                        if (initial_response == NULL)
    1167                          {
    1168                            g_prefix_error (error, "Initial response is malformed: ");
    1169                            /* invalid encoding, disconnect! */
    1170                            g_strfreev (tokens);
    1171                            goto out;
    1172                          }
    1173                      }
    1174  
    1175                    _g_dbus_auth_mechanism_server_initiate (mech,
    1176                                                            initial_response,
    1177                                                            initial_response_len);
    1178                    g_free (initial_response);
    1179                    g_strfreev (tokens);
    1180  
    1181                  change_state:
    1182                    switch (_g_dbus_auth_mechanism_server_get_state (mech))
    1183                      {
    1184                      case G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED:
    1185                        if (require_same_user &&
    1186                            (credentials == NULL ||
    1187                             !g_credentials_is_same_user (credentials, own_credentials, NULL)))
    1188                          {
    1189                            /* disconnect */
    1190                            g_set_error_literal (error,
    1191                                                 G_IO_ERROR,
    1192                                                 G_IO_ERROR_FAILED,
    1193                                                 _("User IDs must be the same for peer and server"));
    1194                            goto out;
    1195                          }
    1196                        else if (observer != NULL &&
    1197                                 !g_dbus_auth_observer_authorize_authenticated_peer (observer,
    1198                                                                                     auth->priv->stream,
    1199                                                                                     credentials))
    1200                          {
    1201                            /* disconnect */
    1202                            g_set_error_literal (error,
    1203                                                 G_IO_ERROR,
    1204                                                 G_IO_ERROR_FAILED,
    1205                                                 _("Cancelled via GDBusAuthObserver::authorize-authenticated-peer"));
    1206                            goto out;
    1207                          }
    1208                        else
    1209                          {
    1210                            s = g_strdup_printf ("OK %s\r\n", guid);
    1211                            debug_print ("SERVER: writing '%s'", s);
    1212                            if (!g_data_output_stream_put_string (dos, s, cancellable, error))
    1213                              {
    1214                                g_free (s);
    1215                                goto out;
    1216                              }
    1217                            g_free (s);
    1218                            state = SERVER_STATE_WAITING_FOR_BEGIN;
    1219                          }
    1220                        break;
    1221  
    1222                      case G_DBUS_AUTH_MECHANISM_STATE_REJECTED:
    1223                        s = get_auth_mechanisms (auth, allow_anonymous, "REJECTED ", "\r\n", " ");
    1224                        debug_print ("SERVER: writing '%s'", s);
    1225                        if (!g_data_output_stream_put_string (dos, s, cancellable, error))
    1226                          {
    1227                            g_free (s);
    1228                            goto out;
    1229                          }
    1230                        g_free (s);
    1231                        state = SERVER_STATE_WAITING_FOR_AUTH;
    1232                        break;
    1233  
    1234                      case G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA:
    1235                        state = SERVER_STATE_WAITING_FOR_DATA;
    1236                        break;
    1237  
    1238                      case G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND:
    1239                        {
    1240                          gchar *data;
    1241                          gsize data_len;
    1242  
    1243                          data = _g_dbus_auth_mechanism_server_data_send (mech, &data_len);
    1244  
    1245                          if (data != NULL)
    1246                            {
    1247                              if (data_len == 0)
    1248                                {
    1249                                  s = g_strdup ("DATA\r\n");
    1250                                }
    1251                              else
    1252                                {
    1253                                  gchar *encoded_data = _g_dbus_hexencode (data, data_len);
    1254  
    1255                                  s = g_strdup_printf ("DATA %s\r\n", encoded_data);
    1256                                  g_free (encoded_data);
    1257                                }
    1258  
    1259                              g_free (data);
    1260  
    1261                              debug_print ("SERVER: writing '%s'", s);
    1262                              if (!g_data_output_stream_put_string (dos, s, cancellable, error))
    1263                                {
    1264                                  g_free (s);
    1265                                  goto out;
    1266                                }
    1267                              g_free (s);
    1268                            }
    1269                        }
    1270                        goto change_state;
    1271                        break;
    1272  
    1273                      default:
    1274                        /* TODO */
    1275                        g_assert_not_reached ();
    1276                        break;
    1277                      }
    1278                  }
    1279              }
    1280            else
    1281              {
    1282                g_set_error (error,
    1283                             G_IO_ERROR,
    1284                             G_IO_ERROR_FAILED,
    1285                             "Unexpected line '%s' while in WaitingForAuth state",
    1286                             line);
    1287                g_free (line);
    1288                goto out;
    1289              }
    1290            break;
    1291  
    1292          case SERVER_STATE_WAITING_FOR_DATA:
    1293            debug_print ("SERVER: WaitingForData");
    1294            line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
    1295                                                      &line_length,
    1296                                                      cancellable,
    1297                                                      error);
    1298            debug_print ("SERVER: WaitingForData, read '%s'", line);
    1299            if (line == NULL)
    1300              goto out;
    1301            if (g_str_equal (line, "DATA") || g_str_has_prefix (line, "DATA "))
    1302              {
    1303                gchar *encoded;
    1304                gchar *decoded_data;
    1305                gsize decoded_data_len = 0;
    1306  
    1307                encoded = g_strdup (line + 4);
    1308                g_free (line);
    1309                g_strstrip (encoded);
    1310                decoded_data = hexdecode (encoded, &decoded_data_len, error);
    1311                g_free (encoded);
    1312                if (decoded_data == NULL)
    1313                  {
    1314                    g_prefix_error (error, "DATA response is malformed: ");
    1315                    /* invalid encoding, disconnect! */
    1316                    goto out;
    1317                  }
    1318                _g_dbus_auth_mechanism_server_data_receive (mech, decoded_data, decoded_data_len);
    1319                g_free (decoded_data);
    1320                /* oh man, this goto-crap is so ugly.. really need to rewrite the state machine */
    1321                goto change_state;
    1322              }
    1323            else
    1324              {
    1325                g_set_error (error,
    1326                             G_IO_ERROR,
    1327                             G_IO_ERROR_FAILED,
    1328                             "Unexpected line '%s' while in WaitingForData state",
    1329                             line);
    1330                g_free (line);
    1331              }
    1332            goto out;
    1333  
    1334          case SERVER_STATE_WAITING_FOR_BEGIN:
    1335            debug_print ("SERVER: WaitingForBegin");
    1336            line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
    1337                                                      &line_length,
    1338                                                      cancellable,
    1339                                                      error);
    1340            if (line == NULL)
    1341              goto out;
    1342            debug_print ("SERVER: WaitingForBegin, read '%s'", line);
    1343            if (g_strcmp0 (line, "BEGIN") == 0)
    1344              {
    1345                /* YAY, done! */
    1346                ret = TRUE;
    1347                g_free (line);
    1348                goto out;
    1349              }
    1350            else if (g_strcmp0 (line, "NEGOTIATE_UNIX_FD") == 0)
    1351              {
    1352                g_free (line);
    1353                if (offered_capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
    1354                  {
    1355                    negotiated_capabilities |= G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
    1356                    s = "AGREE_UNIX_FD\r\n";
    1357                    debug_print ("SERVER: writing '%s'", s);
    1358                    if (!g_data_output_stream_put_string (dos, s, cancellable, error))
    1359                      goto out;
    1360                  }
    1361                else
    1362                  {
    1363                    s = "ERROR \"fd passing not offered\"\r\n";
    1364                    debug_print ("SERVER: writing '%s'", s);
    1365                    if (!g_data_output_stream_put_string (dos, s, cancellable, error))
    1366                      goto out;
    1367                  }
    1368              }
    1369            else
    1370              {
    1371                g_debug ("Unexpected line '%s' while in WaitingForBegin state", line);
    1372                g_free (line);
    1373                s = "ERROR \"Unknown Command\"\r\n";
    1374                debug_print ("SERVER: writing '%s'", s);
    1375                if (!g_data_output_stream_put_string (dos, s, cancellable, error))
    1376                  goto out;
    1377              }
    1378            break;
    1379  
    1380          default:
    1381            g_assert_not_reached ();
    1382            break;
    1383          }
    1384      }
    1385  
    1386  
    1387    g_set_error_literal (error,
    1388                         G_IO_ERROR,
    1389                         G_IO_ERROR_FAILED,
    1390                         "Not implemented (server)");
    1391  
    1392   out:
    1393    g_clear_object (&mech);
    1394    g_clear_object (&dos);
    1395    g_clear_object (&own_credentials);
    1396  
    1397    /* ensure return value is FALSE if error is set */
    1398    if (error != NULL && *error != NULL)
    1399      {
    1400        ret = FALSE;
    1401      }
    1402  
    1403    if (ret)
    1404      {
    1405        if (out_negotiated_capabilities != NULL)
    1406          *out_negotiated_capabilities = negotiated_capabilities;
    1407        if (out_received_credentials != NULL)
    1408          *out_received_credentials = credentials != NULL ? g_object_ref (credentials) : NULL;
    1409      }
    1410  
    1411    if (credentials != NULL)
    1412      g_object_unref (credentials);
    1413  
    1414    debug_print ("SERVER: Done, authenticated=%d", ret);
    1415  
    1416    return ret;
    1417  }
    1418  
    1419  /* ---------------------------------------------------------------------------------------------------- */