dbus-auth.c revision 9f1a60dbba69844c0a04b3dd86280352736187ce
1ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang/* -*- mode: C; c-file-style: "gnu" -*- */
2ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang/* dbus-auth.c Authentication
3ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *
4ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * Copyright (C) 2002, 2003 Red Hat Inc.
5ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *
6ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * Licensed under the Academic Free License version 1.2
7ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *
8ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * This program is free software; you can redistribute it and/or modify
9ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * it under the terms of the GNU General Public License as published by
10ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * the Free Software Foundation; either version 2 of the License, or
11ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * (at your option) any later version.
12ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *
13ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * This program is distributed in the hope that it will be useful,
14ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * but WITHOUT ANY WARRANTY; without even the implied warranty of
15ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * GNU General Public License for more details.
17da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
18da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * You should have received a copy of the GNU General Public License
195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * along with this program; if not, write to the Free Software
201184aebb761cbeac9124c37189a80a1a58f04b6bhkuang * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
211184aebb761cbeac9124c37189a80a1a58f04b6bhkuang *
225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang */
232ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include "dbus-auth.h"
24da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "dbus-string.h"
25da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "dbus-list.h"
262ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include "dbus-internals.h"
27da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "dbus-keyring.h"
28ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "dbus-sha.h"
29ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "dbus-userdb.h"
30ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
31ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang/**
32da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @defgroup DBusAuth Authentication
33da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @ingroup  DBusInternals
34da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @brief DBusAuth object
35da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
36da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * DBusAuth manages the authentication negotiation when a connection
37da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * is first established, and also manage any encryption used over a
38da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * connection.
39da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
40da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @todo some SASL profiles require sending the empty string as a
41da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * challenge/response, but we don't currently allow that in our
42ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian * protocol.
43da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
44ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian * @todo DBusAuth really needs to be rewritten as an explicit state
455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * machine. Right now it's too hard to prove to yourself by inspection
46da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * that it works.
47da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
48da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @todo right now sometimes both ends will block waiting for input
49da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * from the other end, e.g. if there's an error during
50da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * DBUS_COOKIE_SHA1.
51da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
52da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @todo the cookie keyring needs to be cached globally not just
53da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * per-auth (which raises threadsafety issues too)
54da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
55da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @todo grep FIXME in dbus-auth.c
56da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
57da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
58da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
59da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @defgroup DBusAuthInternals Authentication implementation details
60da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @ingroup  DBusInternals
61da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @brief DBusAuth implementation details
62da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
63da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * Private details of authentication code.
64da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian *
65da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @{
66da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
67da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
68da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
69da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * Processes a command. Returns whether we had enough memory to
70da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * complete the operation.
71da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
72da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniantypedef dbus_bool_t (* DBusProcessAuthCommandFunction) (DBusAuth         *auth,
73da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                        const DBusString *command,
74da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                        const DBusString *args);
75da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
76da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
77da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * Handler for a given auth protocol command
78da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
79da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniantypedef struct
80da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
81da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  const char *command; /**< Name of the command */
82da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusProcessAuthCommandFunction func; /**< Function to handle the command */
83da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian} DBusAuthCommandHandler;
842ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
85da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
86da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * This function appends an initial client response to the given string
8791037db265ecdd914a26e056cf69207b4f50924ehkuang */
885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangtypedef dbus_bool_t (* DBusInitialResponseFunction)  (DBusAuth         *auth,
89da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                      DBusString       *response);
902ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
9191037db265ecdd914a26e056cf69207b4f50924ehkuang/**
9291037db265ecdd914a26e056cf69207b4f50924ehkuang * This function processes a block of data received from the peer.
93da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * i.e. handles a DATA command.
94da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
95da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniantypedef dbus_bool_t (* DBusAuthDataFunction)     (DBusAuth         *auth,
96da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                  const DBusString *data);
97da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
98da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
99da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * This function encodes a block of data from the peer.
100da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
101da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniantypedef dbus_bool_t (* DBusAuthEncodeFunction)   (DBusAuth         *auth,
102da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                  const DBusString *data,
103da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                  DBusString       *encoded);
104da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
105da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
106da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * This function decodes a block of data from the peer.
107da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
108da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniantypedef dbus_bool_t (* DBusAuthDecodeFunction)   (DBusAuth         *auth,
109da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                  const DBusString *data,
110da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                  DBusString       *decoded);
111da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
112da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
113da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * This function is called when the mechanism is abandoned.
114da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
115da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniantypedef void        (* DBusAuthShutdownFunction) (DBusAuth       *auth);
116da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
117da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
118da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * Virtual table representing a particular auth mechanism.
119da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
120da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniantypedef struct
121da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
122da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  const char *mechanism; /**< Name of the mechanism */
123da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusAuthDataFunction server_data_func; /**< Function on server side for DATA */
124da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusAuthEncodeFunction server_encode_func; /**< Function on server side to encode */
125da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusAuthDecodeFunction server_decode_func; /**< Function on server side to decode */
126da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusAuthShutdownFunction server_shutdown_func; /**< Function on server side to shut down */
127da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusInitialResponseFunction client_initial_response_func; /**< Function on client side to handle initial response */
128da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusAuthDataFunction client_data_func; /**< Function on client side for DATA */
129da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusAuthEncodeFunction client_encode_func; /**< Function on client side for encode */
130da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusAuthDecodeFunction client_decode_func; /**< Function on client side for decode */
131da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusAuthShutdownFunction client_shutdown_func; /**< Function on client side for shutdown */
132da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian} DBusAuthMechanismHandler;
133da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
134da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
135da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * Internal members of DBusAuth.
136da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
1375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstruct DBusAuth
13891037db265ecdd914a26e056cf69207b4f50924ehkuang{
1395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  int refcount;           /**< reference count */
14091037db265ecdd914a26e056cf69207b4f50924ehkuang
14191037db265ecdd914a26e056cf69207b4f50924ehkuang  DBusString incoming;    /**< Incoming data buffer */
142da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString outgoing;    /**< Outgoing data buffer */
143da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
14491037db265ecdd914a26e056cf69207b4f50924ehkuang  const DBusAuthCommandHandler *handlers; /**< Handlers for commands */
1455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
1465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  const DBusAuthMechanismHandler *mech;   /**< Current auth mechanism */
147da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
148da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString identity;                   /**< Current identity we're authorizing
1495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                          *   as.
1505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                          */
151ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
1525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusCredentials credentials;      /**< Credentials read from socket,
153ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                                     * fields may be -1
1545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                     */
1555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
1565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusCredentials authorized_identity; /**< Credentials that are authorized */
157da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
158da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusCredentials desired_identity;    /**< Identity client has requested */
159ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
1605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusString context;               /**< Cookie scope */
161ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  DBusKeyring *keyring;             /**< Keyring for cookie mechanism. */
1625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  int cookie_id;                    /**< ID of cookie to use */
1635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusString challenge;             /**< Challenge sent to client */
1645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
1655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  char **allowed_mechs;             /**< Mechanisms we're allowed to use,
1665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                     * or #NULL if we can use any
1675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                     */
1685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
169ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  unsigned int needed_memory : 1;   /**< We needed memory to continue since last
170ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                                     * successful getting something done
1715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                     */
172da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  unsigned int need_disconnect : 1; /**< We've given up, time to disconnect */
173da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  unsigned int authenticated : 1;   /**< We are authenticated */
1745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  unsigned int authenticated_pending_output : 1; /**< Authenticated once we clear outgoing buffer */
1755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  unsigned int authenticated_pending_begin : 1;  /**< Authenticated once we get BEGIN */
1765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  unsigned int already_got_mechanisms : 1;       /**< Client already got mech list */
1775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */
1785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
1795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang};
180ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
181ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang/**
1825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * "Subclass" of DBusAuth for client side
183ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang */
1845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangtypedef struct
185da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
1865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusAuth base;    /**< Parent class */
187da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
188da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */
189ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
1905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} DBusAuthClient;
191ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
1925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang/**
1935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * "Subclass" of DBusAuth for server side.
1945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang */
1955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangtypedef struct
1965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang{
1975ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusAuth base;    /**< Parent class */
1985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
199ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  int failures;     /**< Number of times client has been rejected */
200ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  int max_failures; /**< Number of times we reject before disconnect */
2015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
202da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian} DBusAuthServer;
203da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
204da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t process_auth         (DBusAuth         *auth,
2055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *command,
2065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *args);
2075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic dbus_bool_t process_cancel       (DBusAuth         *auth,
2085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *command,
2095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *args);
210ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangstatic dbus_bool_t process_begin        (DBusAuth         *auth,
211ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                                         const DBusString *command,
212ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                                         const DBusString *args);
2135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic dbus_bool_t process_data_server  (DBusAuth         *auth,
2145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *command,
2155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *args);
2165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic dbus_bool_t process_error_server (DBusAuth         *auth,
2175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *command,
218da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                         const DBusString *args);
219da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t process_rejected     (DBusAuth         *auth,
220da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                         const DBusString *command,
221da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                         const DBusString *args);
222da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t process_ok           (DBusAuth         *auth,
223da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                         const DBusString *command,
224da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                         const DBusString *args);
225da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t process_data_client  (DBusAuth         *auth,
226ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                                         const DBusString *command,
2275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *args);
228da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t process_error_client (DBusAuth         *auth,
2295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                         const DBusString *command,
230da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                         const DBusString *args);
231da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
232da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
233da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t client_try_next_mechanism (DBusAuth *auth);
234da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t send_rejected             (DBusAuth *auth);
235da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
236da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic DBusAuthCommandHandler
237da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianserver_handlers[] = {
238da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  { "AUTH", process_auth },
239da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  { "CANCEL", process_cancel },
240da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  { "BEGIN", process_begin },
2415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  { "DATA", process_data_server },
242ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  { "ERROR", process_error_server },
243ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  { NULL, NULL }
2445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang};
2455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
2465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic DBusAuthCommandHandler
2475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangclient_handlers[] = {
2485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  { "REJECTED", process_rejected },
2495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  { "OK", process_ok },
2505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  { "DATA", process_data_client },
2515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  { "ERROR", process_error_client },
2525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  { NULL, NULL }
2535ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang};
2545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
2555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang/**
256da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @param auth the auth conversation
257da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @returns #TRUE if the conversation is the server side
258da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
259da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#define DBUS_AUTH_IS_SERVER(auth) ((auth)->handlers == server_handlers)
260da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
261da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @param auth the auth conversation
262da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @returns #TRUE if the conversation is the client side
263da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
264da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#define DBUS_AUTH_IS_CLIENT(auth) ((auth)->handlers == client_handlers)
2655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang/**
2665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * @param auth the auth conversation
267da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @returns auth cast to DBusAuthClient
268da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
269da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#define DBUS_AUTH_CLIENT(auth)    ((DBusAuthClient*)(auth))
270da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/**
2715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * @param auth the auth conversation
272da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * @returns auth cast to DBusAuthServer
2735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang */
2745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define DBUS_AUTH_SERVER(auth)    ((DBusAuthServer*)(auth))
2755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
2765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang/**
2775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * The name of the auth ("client" or "server")
278ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * @param auth the auth conversation
279ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang * @returns a string
280da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
2815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define DBUS_AUTH_NAME(auth)      (DBUS_AUTH_IS_SERVER(auth) ? "server" : "client")
2825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
283ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangstatic DBusAuth*
284da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian_dbus_auth_new (int size)
2855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang{
2865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusAuth *auth;
2875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
288ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  auth = dbus_malloc0 (size);
2895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (auth == NULL)
2905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    return NULL;
2915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
2925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  auth->refcount = 1;
293ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
2945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  _dbus_credentials_clear (&auth->credentials);
295da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_credentials_clear (&auth->authorized_identity);
296da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_credentials_clear (&auth->desired_identity);
297da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
298da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  auth->keyring = NULL;
299da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  auth->cookie_id = -1;
300da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
301da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  /* note that we don't use the max string length feature,
302da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   * because you can't use that feature if you're going to
303da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   * try to recover from out-of-memory (it creates
304ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang   * what looks like unrecoverable inability to alloc
3055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang   * more space in the string). But we do handle
306da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   * overlong buffers in _dbus_auth_do_work().
3075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang   */
308da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
309da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&auth->incoming))
310da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto enomem_0;
311da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
312da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&auth->outgoing))
313da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto enomem_1;
314da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
315da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&auth->identity))
316da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto enomem_2;
317da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
318da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&auth->context))
319da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto enomem_3;
320da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
321ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  if (!_dbus_string_init (&auth->challenge))
322da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto enomem_4;
323da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
324da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  /* default context if none is specified */
325da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))
326da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto enomem_5;
327da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
328da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  return auth;
329da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
330da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian enomem_5:
331da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_free (&auth->challenge);
332da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian enomem_4:
333da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_free (&auth->context);
334ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian enomem_3:
3355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  _dbus_string_free (&auth->identity);
336ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang enomem_2:
337ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  _dbus_string_free (&auth->outgoing);
3385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enomem_1:
339ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  _dbus_string_free (&auth->incoming);
340ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian enomem_0:
341da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  dbus_free (auth);
342da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  return NULL;
343da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian}
344da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
345da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic void
346da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianshutdown_mech (DBusAuth *auth)
347da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
348da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  /* Cancel any auth */
349da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  auth->authenticated_pending_begin = FALSE;
3505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  auth->authenticated = FALSE;
3515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  auth->already_asked_for_initial_response = FALSE;
352da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_set_length (&auth->identity, 0);
353da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
354da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_credentials_clear (&auth->authorized_identity);
355da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_credentials_clear (&auth->desired_identity);
3565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
357da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (auth->mech != NULL)
3585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    {
3595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang      _dbus_verbose ("%s: Shutting down mechanism %s\n",
3605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                     DBUS_AUTH_NAME (auth), auth->mech->mechanism);
3615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
362ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian      if (DBUS_AUTH_IS_CLIENT (auth))
363ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian        (* auth->mech->client_shutdown_func) (auth);
364ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian      else
3655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang        (* auth->mech->server_shutdown_func) (auth);
3665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
367da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      auth->mech = NULL;
3685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    }
3695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang}
3705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
371da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/* Returns TRUE but with an empty string hash if the
3725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * cookie_id isn't known. As with all this code
3735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * TRUE just means we had enough memory.
374ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian */
375ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanianstatic dbus_bool_t
376ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramaniansha1_compute_hash (DBusAuth         *auth,
377ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian                   int               cookie_id,
378ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                   const DBusString *server_challenge,
3795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                   const DBusString *client_challenge,
380ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                   DBusString       *hash)
381da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
382da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString cookie;
383da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString to_hash;
384da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  dbus_bool_t retval;
385da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
386da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_assert (auth->keyring != NULL);
387da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
388da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  retval = FALSE;
389da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
390da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&cookie))
391da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    return FALSE;
392da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
393da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
394da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                  &cookie))
395da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_0;
396da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
397da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (_dbus_string_get_length (&cookie) == 0)
398da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
399da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      retval = TRUE;
400da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      goto out_0;
401da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
402da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
403da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&to_hash))
404da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_0;
405da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
406da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_copy (server_challenge, 0,
407da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                          &to_hash, _dbus_string_get_length (&to_hash)))
408da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_1;
409da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
410da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_append (&to_hash, ":"))
411da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_1;
412da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
413da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_copy (client_challenge, 0,
414da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                          &to_hash, _dbus_string_get_length (&to_hash)))
415da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_1;
416da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
417da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_append (&to_hash, ":"))
418da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_1;
419da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
420da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_copy (&cookie, 0,
421da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                          &to_hash, _dbus_string_get_length (&to_hash)))
422da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_1;
423da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
424da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_sha_compute (&to_hash, hash))
425da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_1;
426da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
427da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  retval = TRUE;
428da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
429da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian out_1:
430da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_zero (&to_hash);
431da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_free (&to_hash);
432da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian out_0:
433da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_zero (&cookie);
434da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_free (&cookie);
435da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  return retval;
436da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian}
437da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
438da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian/** http://www.ietf.org/rfc/rfc2831.txt suggests at least 64 bits of
439da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * entropy, we use 128. This is the number of bytes in the random
440da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian * challenge.
441da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian */
442da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#define N_CHALLENGE_BYTES (128/8)
443da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
444da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t
445da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniansha1_handle_first_client_response (DBusAuth         *auth,
446da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                   const DBusString *data)
447da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
448da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  /* We haven't sent a challenge yet, we're expecting a desired
449da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   * username from the client.
450da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   */
451da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString tmp;
452da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString tmp2;
453da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  dbus_bool_t retval;
454da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  int old_len;
455da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusError error;
456da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
457da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  retval = FALSE;
458da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
459da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_set_length (&auth->challenge, 0);
460da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
461da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (_dbus_string_get_length (data) > 0)
462da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
463da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      if (_dbus_string_get_length (&auth->identity) > 0)
464da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        {
465da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian          /* Tried to send two auth identities, wtf */
466da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian          _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
467da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                         DBUS_AUTH_NAME (auth));
468da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian          return send_rejected (auth);
469da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        }
470da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      else
471da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        {
472da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian          /* this is our auth identity */
473da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian          if (!_dbus_string_copy (data, 0, &auth->identity, 0))
474da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian            return FALSE;
475da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        }
476da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
477da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
478da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_credentials_from_username (data, &auth->desired_identity))
479da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
480da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      _dbus_verbose ("%s: Did not get a valid username from client\n",
481da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                     DBUS_AUTH_NAME (auth));
482da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      return send_rejected (auth);
483da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
484da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
485da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&tmp))
486da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    return FALSE;
487da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
488da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&tmp2))
489da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
490da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      _dbus_string_free (&tmp);
491da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      return FALSE;
492da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
493da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
494da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  old_len = _dbus_string_get_length (&auth->outgoing);
495da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
496da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  /* we cache the keyring for speed, so here we drop it if it's the
497da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   * wrong one. FIXME caching the keyring here is useless since we use
498da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   * a different DBusAuth for every connection.
499da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   */
500da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (auth->keyring &&
501da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      !_dbus_keyring_is_for_user (auth->keyring,
502da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                  data))
503da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
504da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      _dbus_keyring_unref (auth->keyring);
505da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      auth->keyring = NULL;
506da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
507da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
508da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (auth->keyring == NULL)
509da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
510da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      DBusError error;
511da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
512da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      dbus_error_init (&error);
513da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      auth->keyring = _dbus_keyring_new_homedir (data,
514da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                 &auth->context,
515da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                 &error);
516da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
517da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      if (auth->keyring == NULL)
518da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        {
519da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian          if (dbus_error_has_name (&error,
520da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                   DBUS_ERROR_NO_MEMORY))
521da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian            {
522da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian              dbus_error_free (&error);
523da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian              goto out;
5245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang            }
5255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang          else
526ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian            {
527da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian              _DBUS_ASSERT_ERROR_IS_SET (&error);
528da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian              _dbus_verbose ("%s: Error loading keyring: %s\n",
5295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                             DBUS_AUTH_NAME (auth), error.message);
530ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang              if (send_rejected (auth))
5312ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian                retval = TRUE; /* retval is only about mem */
5322ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian              dbus_error_free (&error);
533ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian              goto out;
5345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang            }
5355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang        }
5365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang      else
5375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang        {
5385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang          _dbus_assert (!dbus_error_is_set (&error));
5395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang        }
5405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    }
5415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
5425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  _dbus_assert (auth->keyring != NULL);
543da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
544da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  dbus_error_init (&error);
5455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
5465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (auth->cookie_id < 0)
5475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    {
5485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang      _DBUS_ASSERT_ERROR_IS_SET (&error);
5495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang      _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
550da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                     DBUS_AUTH_NAME (auth), error.message);
5515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang      if (send_rejected (auth))
5525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang        retval = TRUE;
553da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      dbus_error_free (&error);
5545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang      goto out;
555ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
5565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  else
557ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    {
558ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian      _dbus_assert (!dbus_error_is_set (&error));
5595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    }
5605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
5615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (!_dbus_string_copy (&auth->context, 0,
5625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                          &tmp2, _dbus_string_get_length (&tmp2)))
56391037db265ecdd914a26e056cf69207b4f50924ehkuang    goto out;
564ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
5655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (!_dbus_string_append (&tmp2, " "))
5665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    goto out;
5675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
5685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
5695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    goto out;
5705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
5715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (!_dbus_string_append (&tmp2, " "))
5725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    goto out;
573da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
574da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
575da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out;
576da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
577da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_set_length (&auth->challenge, 0);
578da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
579da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out;
580da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
5812ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
5822ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian                                _dbus_string_get_length (&tmp2)))
583ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    goto out;
5845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
5855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (!_dbus_string_append (&auth->outgoing,
5865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                            "DATA "))
5875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    goto out;
5885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
5895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (!_dbus_string_base64_encode (&tmp2, 0, &auth->outgoing,
5905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                   _dbus_string_get_length (&auth->outgoing)))
5915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    goto out;
5925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
593da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_append (&auth->outgoing,
594da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                            "\r\n"))
5955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    goto out;
5965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
5975ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  retval = TRUE;
5985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
5995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang out:
600da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_zero (&tmp);
6015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  _dbus_string_free (&tmp);
6025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  _dbus_string_zero (&tmp2);
603da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_free (&tmp2);
6045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  if (!retval)
6055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang    _dbus_string_set_length (&auth->outgoing, old_len);
6065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  return retval;
607ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian}
608ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
6095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic dbus_bool_t
6105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangsha1_handle_second_client_response (DBusAuth         *auth,
6115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                    const DBusString *data)
6125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang{
6135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  /* We are expecting a response which is the hex-encoded client
6145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang   * challenge, space, then SHA-1 hash of the concatenation of our
6155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang   * challenge, ":", client challenge, ":", secret key, all
6165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang   * hex-encoded.
6175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang   */
6185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  int i;
6195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusString client_challenge;
6205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusString client_hash;
6215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  dbus_bool_t retval;
6225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  DBusString correct_hash;
623da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
624da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  retval = FALSE;
625da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
626da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_find_blank (data, 0, &i))
627da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
628da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      _dbus_verbose ("%s: no space separator in client response\n",
629da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                     DBUS_AUTH_NAME (auth));
630da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      return send_rejected (auth);
631da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
632da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
633da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&client_challenge))
634da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_0;
635da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
636da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&client_hash))
637da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_1;
638da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
639da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
640da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                              0))
641da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_2;
642da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
643da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_skip_blank (data, i, &i);
644da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
645da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_copy_len (data, i,
646da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                              _dbus_string_get_length (data) - i,
647da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                              &client_hash,
648da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                              0))
649da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_2;
650da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
651da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (_dbus_string_get_length (&client_challenge) == 0 ||
652da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      _dbus_string_get_length (&client_hash) == 0)
653da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
654da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      _dbus_verbose ("%s: zero-length client challenge or hash\n",
6555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                     DBUS_AUTH_NAME (auth));
6565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang      if (send_rejected (auth))
657da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        retval = TRUE;
658da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      goto out_2;
659da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
660da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
661da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&correct_hash))
662da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_2;
663da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
664da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!sha1_compute_hash (auth, auth->cookie_id,
6655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                          &auth->challenge,
6665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                          &client_challenge,
6675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                          &correct_hash))
668da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_3;
669da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
670da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  /* if cookie_id was invalid, then we get an empty hash */
671da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (_dbus_string_get_length (&correct_hash) == 0)
672da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
673da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      if (send_rejected (auth))
674da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        retval = TRUE;
675da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      goto out_3;
676da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
677da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
678da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_equal (&client_hash, &correct_hash))
679da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
680da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      if (send_rejected (auth))
681da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        retval = TRUE;
682da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      goto out_3;
683da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
684da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
685da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_append (&auth->outgoing,
686da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                            "OK\r\n"))
687da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_3;
6885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
6895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT" using DBUS_COOKIE_SHA1\n",
6905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                 DBUS_AUTH_NAME (auth), auth->desired_identity.uid);
691da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
692da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  auth->authorized_identity = auth->desired_identity;
693da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  auth->authenticated_pending_begin = TRUE;
694da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  retval = TRUE;
695da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
6962ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian out_3:
697da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_zero (&correct_hash);
6982ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  _dbus_string_free (&correct_hash);
6992ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian out_2:
7002ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  _dbus_string_zero (&client_hash);
701da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_free (&client_hash);
702da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian out_1:
703da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_free (&client_challenge);
704da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian out_0:
705da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  return retval;
7062ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
707da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
7082ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic dbus_bool_t
709da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianhandle_server_data_cookie_sha1_mech (DBusAuth         *auth,
710da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                     const DBusString *data)
711da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
712da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (auth->cookie_id < 0)
713da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    return sha1_handle_first_client_response (auth, data);
7145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  else
715da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    return sha1_handle_second_client_response (auth, data);
7165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang}
7175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
7185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void
719da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianhandle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
720da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
7215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  auth->cookie_id = -1;
7225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  _dbus_string_set_length (&auth->challenge, 0);
7235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang}
724da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
725da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t
726da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianhandle_client_initial_response_cookie_sha1_mech (DBusAuth   *auth,
727da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                                 DBusString *response)
728da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
729da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  const DBusString *username;
730da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  dbus_bool_t retval;
731da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
732da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  retval = FALSE;
733da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
734da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_username_from_current_process (&username))
735da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_0;
736da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
737da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_base64_encode (username, 0,
738da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                   response,
739da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                   _dbus_string_get_length (response)))
740da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_0;
741da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
742da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  retval = TRUE;
743ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
744da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian out_0:
745da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  return retval;
746da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian}
747da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
748da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianstatic dbus_bool_t
749da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianhandle_client_data_cookie_sha1_mech (DBusAuth         *auth,
750da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                                     const DBusString *data)
751da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian{
752da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  /* The data we get from the server should be the cookie context
753da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   * name, the cookie ID, and the server challenge, separated by
754da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   * spaces. We send back our challenge string and the correct hash.
755da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian   */
756da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  dbus_bool_t retval;
757da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString context;
758da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString cookie_id_str;
759da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString server_challenge;
760da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString client_challenge;
761da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString correct_hash;
762da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  DBusString tmp;
763da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  int i, j;
764da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  long val;
765da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  int old_len;
766da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
767da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  retval = FALSE;
768da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
769ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  if (!_dbus_string_find_blank (data, 0, &i))
770ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian    {
771ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian      if (_dbus_string_append (&auth->outgoing,
772da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                               "ERROR \"Server did not send context/ID/challenge properly\"\r\n"))
773da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian        retval = TRUE;
774ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian      goto out_0;
775da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    }
776da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
777da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_init (&context))
778da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_0;
779da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
780da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_copy_len (data, 0, i,
781da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                              &context, 0))
782da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    goto out_1;
783da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian
784da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  _dbus_string_skip_blank (data, i, &i);
785da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian  if (!_dbus_string_find_blank (data, i, &j))
786da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian    {
787da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian      if (_dbus_string_append (&auth->outgoing,
788da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian                               "ERROR \"Server did not send context/ID/challenge properly\"\r\n"))
789ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        retval = TRUE;
790      goto out_1;
791    }
792
793  if (!_dbus_string_init (&cookie_id_str))
794    goto out_1;
795
796  if (!_dbus_string_copy_len (data, i, j - i,
797                              &cookie_id_str, 0))
798    goto out_2;
799
800  if (!_dbus_string_init (&server_challenge))
801    goto out_2;
802
803  i = j;
804  _dbus_string_skip_blank (data, i, &i);
805  j = _dbus_string_get_length (data);
806
807  if (!_dbus_string_copy_len (data, i, j - i,
808                              &server_challenge, 0))
809    goto out_3;
810
811  if (!_dbus_keyring_validate_context (&context))
812    {
813      if (_dbus_string_append (&auth->outgoing,
814                               "ERROR \"Server sent invalid cookie context\"\r\n"))
815        retval = TRUE;
816      goto out_3;
817    }
818
819  if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
820    {
821      if (_dbus_string_append (&auth->outgoing,
822                               "ERROR \"Could not parse cookie ID as an integer\"\r\n"))
823        retval = TRUE;
824      goto out_3;
825    }
826
827  if (_dbus_string_get_length (&server_challenge) == 0)
828    {
829      if (_dbus_string_append (&auth->outgoing,
830                               "ERROR \"Empty server challenge string\"\r\n"))
831        retval = TRUE;
832      goto out_3;
833    }
834
835  if (auth->keyring == NULL)
836    {
837      DBusError error;
838
839      dbus_error_init (&error);
840      auth->keyring = _dbus_keyring_new_homedir (NULL,
841                                                 &context,
842                                                 &error);
843
844      if (auth->keyring == NULL)
845        {
846          if (dbus_error_has_name (&error,
847                                   DBUS_ERROR_NO_MEMORY))
848            {
849              dbus_error_free (&error);
850              goto out_3;
851            }
852          else
853            {
854              _DBUS_ASSERT_ERROR_IS_SET (&error);
855
856              _dbus_verbose ("%s: Error loading keyring: %s\n",
857                             DBUS_AUTH_NAME (auth), error.message);
858
859              if (_dbus_string_append (&auth->outgoing,
860                                       "ERROR \"Could not load cookie file\"\r\n"))
861                retval = TRUE; /* retval is only about mem */
862
863              dbus_error_free (&error);
864              goto out_3;
865            }
866        }
867      else
868        {
869          _dbus_assert (!dbus_error_is_set (&error));
870        }
871    }
872
873  _dbus_assert (auth->keyring != NULL);
874
875  if (!_dbus_string_init (&tmp))
876    goto out_3;
877
878  if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
879    goto out_4;
880
881  if (!_dbus_string_init (&client_challenge))
882    goto out_4;
883
884  if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
885    goto out_5;
886
887  if (!_dbus_string_init (&correct_hash))
888    goto out_5;
889
890  if (!sha1_compute_hash (auth, val,
891                          &server_challenge,
892                          &client_challenge,
893                          &correct_hash))
894    goto out_6;
895
896  if (_dbus_string_get_length (&correct_hash) == 0)
897    {
898      /* couldn't find the cookie ID or something */
899      if (_dbus_string_append (&auth->outgoing,
900                               "ERROR \"Don't have the requested cookie ID\"\r\n"))
901        retval = TRUE;
902      goto out_6;
903    }
904
905  _dbus_string_set_length (&tmp, 0);
906
907  if (!_dbus_string_copy (&client_challenge, 0, &tmp,
908                          _dbus_string_get_length (&tmp)))
909    goto out_6;
910
911  if (!_dbus_string_append (&tmp, " "))
912    goto out_6;
913
914  if (!_dbus_string_copy (&correct_hash, 0, &tmp,
915                          _dbus_string_get_length (&tmp)))
916    goto out_6;
917
918  old_len = _dbus_string_get_length (&auth->outgoing);
919  if (!_dbus_string_append (&auth->outgoing, "DATA "))
920    goto out_6;
921
922  if (!_dbus_string_base64_encode (&tmp, 0,
923                                   &auth->outgoing,
924                                   _dbus_string_get_length (&auth->outgoing)))
925    {
926      _dbus_string_set_length (&auth->outgoing, old_len);
927      goto out_6;
928    }
929
930  if (!_dbus_string_append (&auth->outgoing, "\r\n"))
931    {
932      _dbus_string_set_length (&auth->outgoing, old_len);
933      goto out_6;
934    }
935
936  retval = TRUE;
937
938 out_6:
939  _dbus_string_zero (&correct_hash);
940  _dbus_string_free (&correct_hash);
941 out_5:
942  _dbus_string_free (&client_challenge);
943 out_4:
944  _dbus_string_zero (&tmp);
945  _dbus_string_free (&tmp);
946 out_3:
947  _dbus_string_free (&server_challenge);
948 out_2:
949  _dbus_string_free (&cookie_id_str);
950 out_1:
951  _dbus_string_free (&context);
952 out_0:
953  return retval;
954}
955
956static void
957handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
958{
959  auth->cookie_id = -1;
960  _dbus_string_set_length (&auth->challenge, 0);
961}
962
963static dbus_bool_t
964handle_server_data_external_mech (DBusAuth         *auth,
965                                  const DBusString *data)
966{
967  if (auth->credentials.uid == DBUS_UID_UNSET)
968    {
969      _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
970                     DBUS_AUTH_NAME (auth));
971      return send_rejected (auth);
972    }
973
974  if (_dbus_string_get_length (data) > 0)
975    {
976      if (_dbus_string_get_length (&auth->identity) > 0)
977        {
978          /* Tried to send two auth identities, wtf */
979          _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
980                         DBUS_AUTH_NAME (auth));
981          return send_rejected (auth);
982        }
983      else
984        {
985          /* this is our auth identity */
986          if (!_dbus_string_copy (data, 0, &auth->identity, 0))
987            return FALSE;
988        }
989    }
990
991  /* Poke client for an auth identity, if none given */
992  if (_dbus_string_get_length (&auth->identity) == 0 &&
993      !auth->already_asked_for_initial_response)
994    {
995      if (_dbus_string_append (&auth->outgoing,
996                               "DATA\r\n"))
997        {
998          _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
999                         DBUS_AUTH_NAME (auth));
1000          auth->already_asked_for_initial_response = TRUE;
1001          return TRUE;
1002        }
1003      else
1004        return FALSE;
1005    }
1006
1007  _dbus_credentials_clear (&auth->desired_identity);
1008
1009  /* If auth->identity is still empty here, then client
1010   * responded with an empty string after we poked it for
1011   * an initial response. This means to try to auth the
1012   * identity provided in the credentials.
1013   */
1014  if (_dbus_string_get_length (&auth->identity) == 0)
1015    {
1016      auth->desired_identity.uid = auth->credentials.uid;
1017    }
1018  else
1019    {
1020      if (!_dbus_uid_from_string (&auth->identity,
1021                                  &auth->desired_identity.uid))
1022        {
1023          _dbus_verbose ("%s: could not get credentials from uid string\n",
1024                         DBUS_AUTH_NAME (auth));
1025          return send_rejected (auth);
1026        }
1027    }
1028
1029  if (auth->desired_identity.uid == DBUS_UID_UNSET)
1030    {
1031      _dbus_verbose ("%s: desired user %s is no good\n",
1032                     DBUS_AUTH_NAME (auth),
1033                     _dbus_string_get_const_data (&auth->identity));
1034      return send_rejected (auth);
1035    }
1036
1037  if (_dbus_credentials_match (&auth->desired_identity,
1038                               &auth->credentials))
1039    {
1040      /* client has authenticated */
1041      if (!_dbus_string_append (&auth->outgoing,
1042                                "OK\r\n"))
1043        return FALSE;
1044
1045      _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT
1046                     " matching socket credentials UID "DBUS_UID_FORMAT"\n",
1047                     DBUS_AUTH_NAME (auth),
1048                     auth->desired_identity.uid,
1049                     auth->credentials.uid);
1050
1051      auth->authorized_identity.uid = auth->desired_identity.uid;
1052
1053      auth->authenticated_pending_begin = TRUE;
1054
1055      return TRUE;
1056    }
1057  else
1058    {
1059      _dbus_verbose ("%s: credentials uid="DBUS_UID_FORMAT
1060                     " gid="DBUS_GID_FORMAT
1061                     " do not allow uid="DBUS_UID_FORMAT
1062                     " gid="DBUS_GID_FORMAT"\n",
1063                     DBUS_AUTH_NAME (auth),
1064                     auth->credentials.uid, auth->credentials.gid,
1065                     auth->desired_identity.uid, auth->desired_identity.gid);
1066      return send_rejected (auth);
1067    }
1068}
1069
1070static void
1071handle_server_shutdown_external_mech (DBusAuth *auth)
1072{
1073
1074}
1075
1076static dbus_bool_t
1077handle_client_initial_response_external_mech (DBusAuth         *auth,
1078                                              DBusString       *response)
1079{
1080  /* We always append our UID as an initial response, so the server
1081   * doesn't have to send back an empty challenge to check whether we
1082   * want to specify an identity. i.e. this avoids a round trip that
1083   * the spec for the EXTERNAL mechanism otherwise requires.
1084   */
1085  DBusString plaintext;
1086
1087  if (!_dbus_string_init (&plaintext))
1088    return FALSE;
1089
1090  if (!_dbus_string_append_uint (&plaintext,
1091                                 _dbus_getuid ()))
1092    goto failed;
1093
1094  if (!_dbus_string_base64_encode (&plaintext, 0,
1095                                   response,
1096                                   _dbus_string_get_length (response)))
1097    goto failed;
1098
1099  _dbus_string_free (&plaintext);
1100
1101  return TRUE;
1102
1103 failed:
1104  _dbus_string_free (&plaintext);
1105  return FALSE;
1106}
1107
1108static dbus_bool_t
1109handle_client_data_external_mech (DBusAuth         *auth,
1110                                  const DBusString *data)
1111{
1112
1113  return TRUE;
1114}
1115
1116static void
1117handle_client_shutdown_external_mech (DBusAuth *auth)
1118{
1119
1120}
1121
1122/* Put mechanisms here in order of preference.
1123 * What I eventually want to have is:
1124 *
1125 *  - a mechanism that checks UNIX domain socket credentials
1126 *  - a simple magic cookie mechanism like X11 or ICE
1127 *  - mechanisms that chain to Cyrus SASL, so we can use anything it
1128 *    offers such as Kerberos, X509, whatever.
1129 *
1130 */
1131static const DBusAuthMechanismHandler
1132all_mechanisms[] = {
1133  { "EXTERNAL",
1134    handle_server_data_external_mech,
1135    NULL, NULL,
1136    handle_server_shutdown_external_mech,
1137    handle_client_initial_response_external_mech,
1138    handle_client_data_external_mech,
1139    NULL, NULL,
1140    handle_client_shutdown_external_mech },
1141  { "DBUS_COOKIE_SHA1",
1142    handle_server_data_cookie_sha1_mech,
1143    NULL, NULL,
1144    handle_server_shutdown_cookie_sha1_mech,
1145    handle_client_initial_response_cookie_sha1_mech,
1146    handle_client_data_cookie_sha1_mech,
1147    NULL, NULL,
1148    handle_client_shutdown_cookie_sha1_mech },
1149  { NULL, NULL }
1150};
1151
1152static const DBusAuthMechanismHandler*
1153find_mech (const DBusString  *name,
1154           char             **allowed_mechs)
1155{
1156  int i;
1157
1158  if (allowed_mechs != NULL &&
1159      !_dbus_string_array_contains ((const char**) allowed_mechs,
1160                                    _dbus_string_get_const_data (name)))
1161    return NULL;
1162
1163  i = 0;
1164  while (all_mechanisms[i].mechanism != NULL)
1165    {
1166      if (_dbus_string_equal_c_str (name,
1167                                    all_mechanisms[i].mechanism))
1168
1169        return &all_mechanisms[i];
1170
1171      ++i;
1172    }
1173
1174  return NULL;
1175}
1176
1177static dbus_bool_t
1178send_rejected (DBusAuth *auth)
1179{
1180  DBusString command;
1181  DBusAuthServer *server_auth;
1182  int i;
1183
1184  if (!_dbus_string_init (&command))
1185    return FALSE;
1186
1187  if (!_dbus_string_append (&command,
1188                            "REJECTED"))
1189    goto nomem;
1190
1191  i = 0;
1192  while (all_mechanisms[i].mechanism != NULL)
1193    {
1194      if (!_dbus_string_append (&command,
1195                                " "))
1196        goto nomem;
1197
1198      if (!_dbus_string_append (&command,
1199                                all_mechanisms[i].mechanism))
1200        goto nomem;
1201
1202      ++i;
1203    }
1204
1205  if (!_dbus_string_append (&command, "\r\n"))
1206    goto nomem;
1207
1208  if (!_dbus_string_copy (&command, 0, &auth->outgoing,
1209                          _dbus_string_get_length (&auth->outgoing)))
1210    goto nomem;
1211
1212  shutdown_mech (auth);
1213
1214  _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
1215  server_auth = DBUS_AUTH_SERVER (auth);
1216  server_auth->failures += 1;
1217
1218  _dbus_string_free (&command);
1219
1220  return TRUE;
1221
1222 nomem:
1223  _dbus_string_free (&command);
1224  return FALSE;
1225}
1226
1227static dbus_bool_t
1228process_auth (DBusAuth         *auth,
1229              const DBusString *command,
1230              const DBusString *args)
1231{
1232  if (auth->mech)
1233    {
1234      /* We are already using a mechanism, client is on crack */
1235      if (!_dbus_string_append (&auth->outgoing,
1236                                "ERROR \"Sent AUTH while another AUTH in progress\"\r\n"))
1237        return FALSE;
1238
1239      return TRUE;
1240    }
1241  else if (_dbus_string_get_length (args) == 0)
1242    {
1243      /* No args to the auth, send mechanisms */
1244      if (!send_rejected (auth))
1245        return FALSE;
1246
1247      return TRUE;
1248    }
1249  else
1250    {
1251      int i;
1252      DBusString mech;
1253      DBusString base64_response;
1254      DBusString decoded_response;
1255
1256      _dbus_string_find_blank (args, 0, &i);
1257
1258      if (!_dbus_string_init (&mech))
1259        return FALSE;
1260
1261      if (!_dbus_string_init (&base64_response))
1262        {
1263          _dbus_string_free (&mech);
1264          return FALSE;
1265        }
1266
1267      if (!_dbus_string_init (&decoded_response))
1268        {
1269          _dbus_string_free (&mech);
1270          _dbus_string_free (&base64_response);
1271          return FALSE;
1272        }
1273
1274      if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
1275        goto failed;
1276
1277      if (!_dbus_string_copy (args, i, &base64_response, 0))
1278        goto failed;
1279
1280      if (!_dbus_string_base64_decode (&base64_response, 0,
1281                                       &decoded_response, 0))
1282        goto failed;
1283
1284      auth->mech = find_mech (&mech, auth->allowed_mechs);
1285      if (auth->mech != NULL)
1286        {
1287          _dbus_verbose ("%s: Trying mechanism %s with initial response of %d bytes\n",
1288                         DBUS_AUTH_NAME (auth),
1289                         auth->mech->mechanism,
1290                         _dbus_string_get_length (&decoded_response));
1291
1292          if (!(* auth->mech->server_data_func) (auth,
1293                                                 &decoded_response))
1294            goto failed;
1295        }
1296      else
1297        {
1298          /* Unsupported mechanism */
1299          if (!send_rejected (auth))
1300            goto failed;
1301        }
1302
1303      _dbus_string_free (&mech);
1304      _dbus_string_free (&base64_response);
1305      _dbus_string_free (&decoded_response);
1306
1307      return TRUE;
1308
1309    failed:
1310      auth->mech = NULL;
1311      _dbus_string_free (&mech);
1312      _dbus_string_free (&base64_response);
1313      _dbus_string_free (&decoded_response);
1314      return FALSE;
1315    }
1316}
1317
1318static dbus_bool_t
1319process_cancel (DBusAuth         *auth,
1320                const DBusString *command,
1321                const DBusString *args)
1322{
1323  if (!send_rejected (auth))
1324    return FALSE;
1325
1326  return TRUE;
1327}
1328
1329static dbus_bool_t
1330process_begin (DBusAuth         *auth,
1331               const DBusString *command,
1332               const DBusString *args)
1333{
1334  if (auth->authenticated_pending_begin)
1335    auth->authenticated = TRUE;
1336  else
1337    {
1338      auth->need_disconnect = TRUE; /* client trying to send data before auth,
1339                                     * kick it
1340                                     */
1341      shutdown_mech (auth);
1342    }
1343
1344  return TRUE;
1345}
1346
1347static dbus_bool_t
1348process_data_server (DBusAuth         *auth,
1349                     const DBusString *command,
1350                     const DBusString *args)
1351{
1352  if (auth->mech != NULL)
1353    {
1354      DBusString decoded;
1355
1356      if (!_dbus_string_init (&decoded))
1357        return FALSE;
1358
1359      if (!_dbus_string_base64_decode (args, 0, &decoded, 0))
1360        {
1361          _dbus_string_free (&decoded);
1362          return FALSE;
1363        }
1364
1365#ifdef DBUS_ENABLE_VERBOSE_MODE
1366      if (_dbus_string_validate_ascii (&decoded, 0,
1367                                       _dbus_string_get_length (&decoded)))
1368        _dbus_verbose ("%s: data: '%s'\n",
1369                       DBUS_AUTH_NAME (auth),
1370                       _dbus_string_get_const_data (&decoded));
1371#endif
1372
1373      if (!(* auth->mech->server_data_func) (auth, &decoded))
1374        {
1375          _dbus_string_free (&decoded);
1376          return FALSE;
1377        }
1378
1379      _dbus_string_free (&decoded);
1380    }
1381  else
1382    {
1383      if (!_dbus_string_append (&auth->outgoing,
1384                                "ERROR \"Not currently in an auth conversation\"\r\n"))
1385        return FALSE;
1386    }
1387
1388  return TRUE;
1389}
1390
1391static dbus_bool_t
1392process_error_server (DBusAuth         *auth,
1393                      const DBusString *command,
1394                      const DBusString *args)
1395{
1396  /* Server got error from client, reject the auth,
1397   * as we don't have anything more intelligent to do.
1398   */
1399  if (!send_rejected (auth))
1400    return FALSE;
1401
1402  return TRUE;
1403}
1404
1405/* return FALSE if no memory, TRUE if all OK */
1406static dbus_bool_t
1407get_word (const DBusString *str,
1408          int              *start,
1409          DBusString       *word)
1410{
1411  int i;
1412
1413  _dbus_string_skip_blank (str, *start, start);
1414  _dbus_string_find_blank (str, *start, &i);
1415
1416  if (i > *start)
1417    {
1418      if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
1419        return FALSE;
1420
1421      *start = i;
1422    }
1423
1424  return TRUE;
1425}
1426
1427static dbus_bool_t
1428record_mechanisms (DBusAuth         *auth,
1429                   const DBusString *command,
1430                   const DBusString *args)
1431{
1432  int next;
1433  int len;
1434
1435  if (auth->already_got_mechanisms)
1436    return TRUE;
1437
1438  len = _dbus_string_get_length (args);
1439
1440  next = 0;
1441  while (next < len)
1442    {
1443      DBusString m;
1444      const DBusAuthMechanismHandler *mech;
1445
1446      if (!_dbus_string_init (&m))
1447        goto nomem;
1448
1449      if (!get_word (args, &next, &m))
1450        {
1451          _dbus_string_free (&m);
1452          goto nomem;
1453        }
1454
1455      mech = find_mech (&m, auth->allowed_mechs);
1456
1457      if (mech != NULL)
1458        {
1459          /* FIXME right now we try mechanisms in the order
1460           * the server lists them; should we do them in
1461           * some more deterministic order?
1462           *
1463           * Probably in all_mechanisms order, our order of
1464           * preference. Of course when the server is us,
1465           * it lists things in that order anyhow.
1466           */
1467
1468          _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
1469                         DBUS_AUTH_NAME (auth), mech->mechanism);
1470
1471          if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
1472                                  (void*) mech))
1473            {
1474              _dbus_string_free (&m);
1475              goto nomem;
1476            }
1477        }
1478      else
1479        {
1480          _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
1481                         DBUS_AUTH_NAME (auth),
1482                         _dbus_string_get_const_data (&m));
1483        }
1484
1485      _dbus_string_free (&m);
1486    }
1487
1488  auth->already_got_mechanisms = TRUE;
1489
1490  return TRUE;
1491
1492 nomem:
1493  _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
1494
1495  return FALSE;
1496}
1497
1498static dbus_bool_t
1499client_try_next_mechanism (DBusAuth *auth)
1500{
1501  const DBusAuthMechanismHandler *mech;
1502  DBusString auth_command;
1503  DBusAuthClient *client;
1504
1505  client = DBUS_AUTH_CLIENT (auth);
1506
1507  /* Pop any mechs not in the list of allowed mechanisms */
1508  mech = NULL;
1509  while (client->mechs_to_try != NULL)
1510    {
1511      mech = client->mechs_to_try->data;
1512
1513      if (auth->allowed_mechs != NULL &&
1514          !_dbus_string_array_contains ((const char**) auth->allowed_mechs,
1515                                        mech->mechanism))
1516        {
1517          /* don't try this one after all */
1518          _dbus_verbose ("%s: Mechanism %s isn't in the list of allowed mechanisms\n",
1519                         DBUS_AUTH_NAME (auth), mech->mechanism);
1520          mech = NULL;
1521          _dbus_list_pop_first (& client->mechs_to_try);
1522        }
1523      else
1524        break; /* we'll try this one */
1525    }
1526
1527  if (mech == NULL)
1528    return FALSE;
1529
1530  if (!_dbus_string_init (&auth_command))
1531    return FALSE;
1532
1533  if (!_dbus_string_append (&auth_command,
1534                            "AUTH "))
1535    {
1536      _dbus_string_free (&auth_command);
1537      return FALSE;
1538    }
1539
1540  if (!_dbus_string_append (&auth_command,
1541                            mech->mechanism))
1542    {
1543      _dbus_string_free (&auth_command);
1544      return FALSE;
1545    }
1546
1547  if (mech->client_initial_response_func != NULL)
1548    {
1549      if (!_dbus_string_append (&auth_command, " "))
1550        {
1551          _dbus_string_free (&auth_command);
1552          return FALSE;
1553        }
1554
1555      if (!(* mech->client_initial_response_func) (auth, &auth_command))
1556        {
1557          _dbus_string_free (&auth_command);
1558          return FALSE;
1559        }
1560    }
1561
1562  if (!_dbus_string_append (&auth_command,
1563                            "\r\n"))
1564    {
1565      _dbus_string_free (&auth_command);
1566      return FALSE;
1567    }
1568
1569  if (!_dbus_string_copy (&auth_command, 0,
1570                          &auth->outgoing,
1571                          _dbus_string_get_length (&auth->outgoing)))
1572    {
1573      _dbus_string_free (&auth_command);
1574      return FALSE;
1575    }
1576
1577  auth->mech = mech;
1578  _dbus_list_pop_first (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
1579
1580  _dbus_verbose ("%s: Trying mechanism %s\n",
1581                 DBUS_AUTH_NAME (auth),
1582                 auth->mech->mechanism);
1583
1584  _dbus_string_free (&auth_command);
1585
1586  return TRUE;
1587}
1588
1589static dbus_bool_t
1590process_rejected (DBusAuth         *auth,
1591                  const DBusString *command,
1592                  const DBusString *args)
1593{
1594  shutdown_mech (auth);
1595
1596  if (!auth->already_got_mechanisms)
1597    {
1598      if (!record_mechanisms (auth, command, args))
1599        return FALSE;
1600    }
1601
1602  if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
1603    {
1604      if (!client_try_next_mechanism (auth))
1605        return FALSE;
1606    }
1607  else
1608    {
1609      /* Give up */
1610      auth->need_disconnect = TRUE;
1611    }
1612
1613  return TRUE;
1614}
1615
1616static dbus_bool_t
1617process_ok (DBusAuth         *auth,
1618            const DBusString *command,
1619            const DBusString *args)
1620{
1621  if (!_dbus_string_append (&auth->outgoing,
1622                            "BEGIN\r\n"))
1623    return FALSE;
1624
1625  auth->authenticated_pending_output = TRUE;
1626
1627  return TRUE;
1628}
1629
1630static dbus_bool_t
1631process_data_client (DBusAuth         *auth,
1632                     const DBusString *command,
1633                     const DBusString *args)
1634{
1635  if (auth->mech != NULL)
1636    {
1637      DBusString decoded;
1638
1639      if (!_dbus_string_init (&decoded))
1640        return FALSE;
1641
1642      if (!_dbus_string_base64_decode (args, 0, &decoded, 0))
1643        {
1644          _dbus_string_free (&decoded);
1645          return FALSE;
1646        }
1647
1648#ifdef DBUS_ENABLE_VERBOSE_MODE
1649      if (_dbus_string_validate_ascii (&decoded, 0,
1650                                       _dbus_string_get_length (&decoded)))
1651        {
1652          _dbus_verbose ("%s: data: '%s'\n",
1653                         DBUS_AUTH_NAME (auth),
1654                         _dbus_string_get_const_data (&decoded));
1655        }
1656#endif
1657
1658      if (!(* auth->mech->client_data_func) (auth, &decoded))
1659        {
1660          _dbus_string_free (&decoded);
1661          return FALSE;
1662        }
1663
1664      _dbus_string_free (&decoded);
1665    }
1666  else
1667    {
1668      if (!_dbus_string_append (&auth->outgoing,
1669                                "ERROR \"Got DATA when not in an auth exchange\"\r\n"))
1670        return FALSE;
1671    }
1672
1673  return TRUE;
1674}
1675
1676static dbus_bool_t
1677process_error_client (DBusAuth         *auth,
1678                      const DBusString *command,
1679                      const DBusString *args)
1680{
1681  /* Cancel current mechanism, as we don't have anything
1682   * more clever to do.
1683   */
1684  if (!_dbus_string_append (&auth->outgoing,
1685                            "CANCEL\r\n"))
1686    return FALSE;
1687
1688  return TRUE;
1689}
1690
1691static dbus_bool_t
1692process_unknown (DBusAuth         *auth,
1693                 const DBusString *command,
1694                 const DBusString *args)
1695{
1696  if (!_dbus_string_append (&auth->outgoing,
1697                            "ERROR \"Unknown command\"\r\n"))
1698    return FALSE;
1699
1700  return TRUE;
1701}
1702
1703/* returns whether to call it again right away */
1704static dbus_bool_t
1705process_command (DBusAuth *auth)
1706{
1707  DBusString command;
1708  DBusString args;
1709  int eol;
1710  int i, j;
1711  dbus_bool_t retval;
1712
1713  /* _dbus_verbose ("%s:   trying process_command()\n"); */
1714
1715  retval = FALSE;
1716
1717  eol = 0;
1718  if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
1719    return FALSE;
1720
1721  if (!_dbus_string_init (&command))
1722    {
1723      auth->needed_memory = TRUE;
1724      return FALSE;
1725    }
1726
1727  if (!_dbus_string_init (&args))
1728    {
1729      _dbus_string_free (&command);
1730      auth->needed_memory = TRUE;
1731      return FALSE;
1732    }
1733
1734  if (eol > _DBUS_ONE_MEGABYTE)
1735    {
1736      /* This is a giant line, someone is trying to hose us. */
1737      if (!_dbus_string_append (&auth->outgoing, "ERROR \"Command too long\"\r\n"))
1738        goto out;
1739      else
1740        goto next_command;
1741    }
1742
1743  if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &command, 0))
1744    goto out;
1745
1746  if (!_dbus_string_validate_ascii (&command, 0,
1747                                    _dbus_string_get_length (&command)))
1748    {
1749      _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
1750                     DBUS_AUTH_NAME (auth));
1751      if (!_dbus_string_append (&auth->outgoing, "ERROR \"Command contained non-ASCII\"\r\n"))
1752        goto out;
1753      else
1754        goto next_command;
1755    }
1756
1757  _dbus_verbose ("%s: got command \"%s\"\n",
1758                 DBUS_AUTH_NAME (auth),
1759                 _dbus_string_get_const_data (&command));
1760
1761  _dbus_string_find_blank (&command, 0, &i);
1762  _dbus_string_skip_blank (&command, i, &j);
1763
1764  if (j > i)
1765    _dbus_string_delete (&command, i, j - i);
1766
1767  if (!_dbus_string_move (&command, i, &args, 0))
1768    goto out;
1769
1770  i = 0;
1771  while (auth->handlers[i].command != NULL)
1772    {
1773      if (_dbus_string_equal_c_str (&command,
1774                                    auth->handlers[i].command))
1775        {
1776          _dbus_verbose ("%s: Processing auth command %s\n",
1777                         DBUS_AUTH_NAME (auth),
1778                         auth->handlers[i].command);
1779
1780          if (!(* auth->handlers[i].func) (auth, &command, &args))
1781            goto out;
1782
1783          break;
1784        }
1785      ++i;
1786    }
1787
1788  if (auth->handlers[i].command == NULL)
1789    {
1790      if (!process_unknown (auth, &command, &args))
1791        goto out;
1792    }
1793
1794 next_command:
1795
1796  /* We've succeeded in processing the whole command so drop it out
1797   * of the incoming buffer and return TRUE to try another command.
1798   */
1799
1800  _dbus_string_delete (&auth->incoming, 0, eol);
1801
1802  /* kill the \r\n */
1803  _dbus_string_delete (&auth->incoming, 0, 2);
1804
1805  retval = TRUE;
1806
1807 out:
1808  _dbus_string_free (&args);
1809  _dbus_string_free (&command);
1810
1811  if (!retval)
1812    auth->needed_memory = TRUE;
1813  else
1814    auth->needed_memory = FALSE;
1815
1816  return retval;
1817}
1818
1819
1820/** @} */
1821
1822/**
1823 * @addtogroup DBusAuth
1824 * @{
1825 */
1826
1827/**
1828 * Creates a new auth conversation object for the server side.
1829 * See doc/dbus-sasl-profile.txt for full details on what
1830 * this object does.
1831 *
1832 * @returns the new object or #NULL if no memory
1833 */
1834DBusAuth*
1835_dbus_auth_server_new (void)
1836{
1837  DBusAuth *auth;
1838  DBusAuthServer *server_auth;
1839
1840  auth = _dbus_auth_new (sizeof (DBusAuthServer));
1841  if (auth == NULL)
1842    return NULL;
1843
1844  auth->handlers = server_handlers;
1845
1846  server_auth = DBUS_AUTH_SERVER (auth);
1847
1848  /* perhaps this should be per-mechanism with a lower
1849   * max
1850   */
1851  server_auth->failures = 0;
1852  server_auth->max_failures = 6;
1853
1854  return auth;
1855}
1856
1857/**
1858 * Creates a new auth conversation object for the client side.
1859 * See doc/dbus-sasl-profile.txt for full details on what
1860 * this object does.
1861 *
1862 * @returns the new object or #NULL if no memory
1863 */
1864DBusAuth*
1865_dbus_auth_client_new (void)
1866{
1867  DBusAuth *auth;
1868
1869  auth = _dbus_auth_new (sizeof (DBusAuthClient));
1870  if (auth == NULL)
1871    return NULL;
1872
1873  auth->handlers = client_handlers;
1874
1875  /* Add a default mechanism to try */
1876  if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
1877                          (void*) &all_mechanisms[0]))
1878    {
1879      _dbus_auth_unref (auth);
1880      return NULL;
1881    }
1882
1883  /* Now try the mechanism we just added */
1884  if (!client_try_next_mechanism (auth))
1885    {
1886      _dbus_auth_unref (auth);
1887      return NULL;
1888    }
1889
1890  return auth;
1891}
1892
1893/**
1894 * Increments the refcount of an auth object.
1895 *
1896 * @param auth the auth conversation
1897 * @returns the auth conversation
1898 */
1899DBusAuth *
1900_dbus_auth_ref (DBusAuth *auth)
1901{
1902  _dbus_assert (auth != NULL);
1903
1904  auth->refcount += 1;
1905
1906  return auth;
1907}
1908
1909/**
1910 * Decrements the refcount of an auth object.
1911 *
1912 * @param auth the auth conversation
1913 */
1914void
1915_dbus_auth_unref (DBusAuth *auth)
1916{
1917  _dbus_assert (auth != NULL);
1918  _dbus_assert (auth->refcount > 0);
1919
1920  auth->refcount -= 1;
1921  if (auth->refcount == 0)
1922    {
1923      shutdown_mech (auth);
1924
1925      if (DBUS_AUTH_IS_CLIENT (auth))
1926        {
1927          _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
1928        }
1929
1930      if (auth->keyring)
1931        _dbus_keyring_unref (auth->keyring);
1932
1933      _dbus_string_free (&auth->context);
1934      _dbus_string_free (&auth->challenge);
1935      _dbus_string_free (&auth->identity);
1936      _dbus_string_free (&auth->incoming);
1937      _dbus_string_free (&auth->outgoing);
1938
1939      dbus_free_string_array (auth->allowed_mechs);
1940
1941      dbus_free (auth);
1942    }
1943}
1944
1945/**
1946 * Sets an array of authentication mechanism names
1947 * that we are willing to use.
1948 *
1949 * @param auth the auth conversation
1950 * @param mechanisms #NULL-terminated array of mechanism names
1951 * @returns #FALSE if no memory
1952 */
1953dbus_bool_t
1954_dbus_auth_set_mechanisms (DBusAuth    *auth,
1955                           const char **mechanisms)
1956{
1957  char **copy;
1958
1959  if (mechanisms != NULL)
1960    {
1961      copy = _dbus_dup_string_array (mechanisms);
1962      if (copy == NULL)
1963        return FALSE;
1964    }
1965  else
1966    copy = NULL;
1967
1968  dbus_free_string_array (auth->allowed_mechs);
1969
1970  auth->allowed_mechs = copy;
1971
1972  return TRUE;
1973}
1974
1975/**
1976 * @param auth the auth conversation object
1977 * @returns #TRUE if we're in a final state
1978 */
1979#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->need_disconnect || (auth)->authenticated)
1980
1981/**
1982 * Analyzes buffered input and moves the auth conversation forward,
1983 * returning the new state of the auth conversation.
1984 *
1985 * @param auth the auth conversation
1986 * @returns the new state
1987 */
1988DBusAuthState
1989_dbus_auth_do_work (DBusAuth *auth)
1990{
1991  auth->needed_memory = FALSE;
1992
1993  /* Max amount we'll buffer up before deciding someone's on crack */
1994#define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
1995
1996  do
1997    {
1998      if (DBUS_AUTH_IN_END_STATE (auth))
1999        break;
2000
2001      if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
2002          _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
2003        {
2004          auth->need_disconnect = TRUE;
2005          _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
2006                         DBUS_AUTH_NAME (auth));
2007          break;
2008        }
2009
2010      if (auth->mech == NULL &&
2011          auth->already_got_mechanisms &&
2012          DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL)
2013        {
2014          auth->need_disconnect = TRUE;
2015          _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
2016                         DBUS_AUTH_NAME (auth));
2017          break;
2018        }
2019    }
2020  while (process_command (auth));
2021
2022  if (DBUS_AUTH_IS_SERVER (auth) &&
2023      DBUS_AUTH_SERVER (auth)->failures >=
2024      DBUS_AUTH_SERVER (auth)->max_failures)
2025    auth->need_disconnect = TRUE;
2026
2027  if (auth->need_disconnect)
2028    return DBUS_AUTH_STATE_NEED_DISCONNECT;
2029  else if (auth->authenticated)
2030    {
2031      if (_dbus_string_get_length (&auth->incoming) > 0)
2032        return DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES;
2033      else
2034        return DBUS_AUTH_STATE_AUTHENTICATED;
2035    }
2036  else if (auth->needed_memory)
2037    return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
2038  else if (_dbus_string_get_length (&auth->outgoing) > 0)
2039    return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
2040  else
2041    return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
2042}
2043
2044/**
2045 * Gets bytes that need to be sent to the peer we're conversing with.
2046 * After writing some bytes, _dbus_auth_bytes_sent() must be called
2047 * to notify the auth object that they were written.
2048 *
2049 * @param auth the auth conversation
2050 * @param str return location for a ref to the buffer to send
2051 * @returns #FALSE if nothing to send
2052 */
2053dbus_bool_t
2054_dbus_auth_get_bytes_to_send (DBusAuth          *auth,
2055                              const DBusString **str)
2056{
2057  _dbus_assert (auth != NULL);
2058  _dbus_assert (str != NULL);
2059
2060  *str = NULL;
2061
2062  if (DBUS_AUTH_IN_END_STATE (auth))
2063    return FALSE;
2064
2065  if (_dbus_string_get_length (&auth->outgoing) == 0)
2066    return FALSE;
2067
2068  *str = &auth->outgoing;
2069
2070  return TRUE;
2071}
2072
2073/**
2074 * Notifies the auth conversation object that
2075 * the given number of bytes of the outgoing buffer
2076 * have been written out.
2077 *
2078 * @param auth the auth conversation
2079 * @param bytes_sent number of bytes written out
2080 */
2081void
2082_dbus_auth_bytes_sent (DBusAuth *auth,
2083                       int       bytes_sent)
2084{
2085  _dbus_verbose ("%s: Sent %d bytes of: %s\n",
2086                 DBUS_AUTH_NAME (auth),
2087                 bytes_sent,
2088                 _dbus_string_get_const_data (&auth->outgoing));
2089
2090  _dbus_string_delete (&auth->outgoing,
2091                       0, bytes_sent);
2092
2093  if (auth->authenticated_pending_output &&
2094      _dbus_string_get_length (&auth->outgoing) == 0)
2095    auth->authenticated = TRUE;
2096}
2097
2098/**
2099 * Get a buffer to be used for reading bytes from the peer we're conversing
2100 * with. Bytes should be appended to this buffer.
2101 *
2102 * @param auth the auth conversation
2103 * @param buffer return location for buffer to append bytes to
2104 */
2105void
2106_dbus_auth_get_buffer (DBusAuth     *auth,
2107                       DBusString **buffer)
2108{
2109  _dbus_assert (auth != NULL);
2110  _dbus_assert (!auth->buffer_outstanding);
2111
2112  *buffer = &auth->incoming;
2113
2114  auth->buffer_outstanding = TRUE;
2115}
2116
2117/**
2118 * Returns a buffer with new data read into it.
2119 *
2120 * @param auth the auth conversation
2121 * @param buffer the buffer being returned
2122 * @param bytes_read number of new bytes added
2123 */
2124void
2125_dbus_auth_return_buffer (DBusAuth               *auth,
2126                          DBusString             *buffer,
2127                          int                     bytes_read)
2128{
2129  _dbus_assert (buffer == &auth->incoming);
2130  _dbus_assert (auth->buffer_outstanding);
2131
2132  auth->buffer_outstanding = FALSE;
2133}
2134
2135/**
2136 * Returns leftover bytes that were not used as part of the auth
2137 * conversation.  These bytes will be part of the message stream
2138 * instead. This function may not be called until authentication has
2139 * succeeded.
2140 *
2141 * @param auth the auth conversation
2142 * @param str return location for pointer to string of unused bytes
2143 */
2144void
2145_dbus_auth_get_unused_bytes (DBusAuth           *auth,
2146                             const DBusString **str)
2147{
2148  if (!DBUS_AUTH_IN_END_STATE (auth))
2149    return;
2150
2151  *str = &auth->incoming;
2152}
2153
2154
2155/**
2156 * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes()
2157 * after we've gotten them and successfully moved them elsewhere.
2158 *
2159 * @param auth the auth conversation
2160 */
2161void
2162_dbus_auth_delete_unused_bytes (DBusAuth *auth)
2163{
2164  if (!DBUS_AUTH_IN_END_STATE (auth))
2165    return;
2166
2167  _dbus_string_set_length (&auth->incoming, 0);
2168}
2169
2170/**
2171 * Called post-authentication, indicates whether we need to encode
2172 * the message stream with _dbus_auth_encode_data() prior to
2173 * sending it to the peer.
2174 *
2175 * @param auth the auth conversation
2176 * @returns #TRUE if we need to encode the stream
2177 */
2178dbus_bool_t
2179_dbus_auth_needs_encoding (DBusAuth *auth)
2180{
2181  if (!auth->authenticated)
2182    return FALSE;
2183
2184  if (auth->mech != NULL)
2185    {
2186      if (DBUS_AUTH_IS_CLIENT (auth))
2187        return auth->mech->client_encode_func != NULL;
2188      else
2189        return auth->mech->server_encode_func != NULL;
2190    }
2191  else
2192    return FALSE;
2193}
2194
2195/**
2196 * Called post-authentication, encodes a block of bytes for sending to
2197 * the peer. If no encoding was negotiated, just copies the bytes
2198 * (you can avoid this by checking _dbus_auth_needs_encoding()).
2199 *
2200 * @param auth the auth conversation
2201 * @param plaintext the plain text data
2202 * @param encoded initialized string to where encoded data is appended
2203 * @returns #TRUE if we had enough memory and successfully encoded
2204 */
2205dbus_bool_t
2206_dbus_auth_encode_data (DBusAuth         *auth,
2207                        const DBusString *plaintext,
2208                        DBusString       *encoded)
2209{
2210  _dbus_assert (plaintext != encoded);
2211
2212  if (!auth->authenticated)
2213    return FALSE;
2214
2215  if (_dbus_auth_needs_encoding (auth))
2216    {
2217      if (DBUS_AUTH_IS_CLIENT (auth))
2218        return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
2219      else
2220        return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
2221    }
2222  else
2223    {
2224      return _dbus_string_copy (plaintext, 0, encoded,
2225                                _dbus_string_get_length (encoded));
2226    }
2227}
2228
2229/**
2230 * Called post-authentication, indicates whether we need to decode
2231 * the message stream with _dbus_auth_decode_data() after
2232 * receiving it from the peer.
2233 *
2234 * @param auth the auth conversation
2235 * @returns #TRUE if we need to encode the stream
2236 */
2237dbus_bool_t
2238_dbus_auth_needs_decoding (DBusAuth *auth)
2239{
2240  if (!auth->authenticated)
2241    return FALSE;
2242
2243  if (auth->mech != NULL)
2244    {
2245      if (DBUS_AUTH_IS_CLIENT (auth))
2246        return auth->mech->client_decode_func != NULL;
2247      else
2248        return auth->mech->server_decode_func != NULL;
2249    }
2250  else
2251    return FALSE;
2252}
2253
2254
2255/**
2256 * Called post-authentication, decodes a block of bytes received from
2257 * the peer. If no encoding was negotiated, just copies the bytes (you
2258 * can avoid this by checking _dbus_auth_needs_decoding()).
2259 *
2260 * @todo We need to be able to distinguish "out of memory" error
2261 * from "the data is hosed" error.
2262 *
2263 * @param auth the auth conversation
2264 * @param encoded the encoded data
2265 * @param plaintext initialized string where decoded data is appended
2266 * @returns #TRUE if we had enough memory and successfully decoded
2267 */
2268dbus_bool_t
2269_dbus_auth_decode_data (DBusAuth         *auth,
2270                        const DBusString *encoded,
2271                        DBusString       *plaintext)
2272{
2273  _dbus_assert (plaintext != encoded);
2274
2275  if (!auth->authenticated)
2276    return FALSE;
2277
2278  if (_dbus_auth_needs_decoding (auth))
2279    {
2280      if (DBUS_AUTH_IS_CLIENT (auth))
2281        return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
2282      else
2283        return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
2284    }
2285  else
2286    {
2287      return _dbus_string_copy (encoded, 0, plaintext,
2288                                _dbus_string_get_length (plaintext));
2289    }
2290}
2291
2292/**
2293 * Sets credentials received via reliable means from the operating
2294 * system.
2295 *
2296 * @param auth the auth conversation
2297 * @param credentials the credentials received
2298 */
2299void
2300_dbus_auth_set_credentials (DBusAuth               *auth,
2301                            const DBusCredentials  *credentials)
2302{
2303  auth->credentials = *credentials;
2304}
2305
2306/**
2307 * Gets the identity we authorized the client as.  Apps may have
2308 * different policies as to what identities they allow.
2309 *
2310 * @param auth the auth conversation
2311 * @param credentials the credentials we've authorized
2312 */
2313void
2314_dbus_auth_get_identity (DBusAuth               *auth,
2315                         DBusCredentials        *credentials)
2316{
2317  if (auth->authenticated)
2318    *credentials = auth->authorized_identity;
2319  else
2320    _dbus_credentials_clear (credentials);
2321}
2322
2323/**
2324 * Sets the "authentication context" which scopes cookies
2325 * with the DBUS_COOKIE_SHA1 auth mechanism for example.
2326 *
2327 * @param auth the auth conversation
2328 * @param context the context
2329 * @returns #FALSE if no memory
2330 */
2331dbus_bool_t
2332_dbus_auth_set_context (DBusAuth               *auth,
2333                        const DBusString       *context)
2334{
2335  return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
2336                                   &auth->context, 0, _dbus_string_get_length (context));
2337}
2338
2339/** @} */
2340
2341#ifdef DBUS_BUILD_TESTS
2342#include "dbus-test.h"
2343#include "dbus-auth-script.h"
2344#include <stdio.h>
2345
2346static dbus_bool_t
2347process_test_subdir (const DBusString          *test_base_dir,
2348                     const char                *subdir)
2349{
2350  DBusString test_directory;
2351  DBusString filename;
2352  DBusDirIter *dir;
2353  dbus_bool_t retval;
2354  DBusError error;
2355
2356  retval = FALSE;
2357  dir = NULL;
2358
2359  if (!_dbus_string_init (&test_directory))
2360    _dbus_assert_not_reached ("didn't allocate test_directory\n");
2361
2362  _dbus_string_init_const (&filename, subdir);
2363
2364  if (!_dbus_string_copy (test_base_dir, 0,
2365                          &test_directory, 0))
2366    _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2367
2368  if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2369    _dbus_assert_not_reached ("couldn't allocate full path");
2370
2371  _dbus_string_free (&filename);
2372  if (!_dbus_string_init (&filename))
2373    _dbus_assert_not_reached ("didn't allocate filename string\n");
2374
2375  dbus_error_init (&error);
2376  dir = _dbus_directory_open (&test_directory, &error);
2377  if (dir == NULL)
2378    {
2379      _dbus_warn ("Could not open %s: %s\n",
2380                  _dbus_string_get_const_data (&test_directory),
2381                  error.message);
2382      dbus_error_free (&error);
2383      goto failed;
2384    }
2385
2386  printf ("Testing %s:\n", subdir);
2387
2388 next:
2389  while (_dbus_directory_get_next_file (dir, &filename, &error))
2390    {
2391      DBusString full_path;
2392
2393      if (!_dbus_string_init (&full_path))
2394        _dbus_assert_not_reached ("couldn't init string");
2395
2396      if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2397        _dbus_assert_not_reached ("couldn't copy dir to full_path");
2398
2399      if (!_dbus_concat_dir_and_file (&full_path, &filename))
2400        _dbus_assert_not_reached ("couldn't concat file to dir");
2401
2402      if (!_dbus_string_ends_with_c_str (&filename, ".auth-script"))
2403        {
2404          _dbus_verbose ("Skipping non-.auth-script file %s\n",
2405                         _dbus_string_get_const_data (&filename));
2406	  _dbus_string_free (&full_path);
2407          goto next;
2408        }
2409
2410      printf ("    %s\n", _dbus_string_get_const_data (&filename));
2411
2412      if (!_dbus_auth_script_run (&full_path))
2413        {
2414          _dbus_string_free (&full_path);
2415          goto failed;
2416        }
2417      else
2418        _dbus_string_free (&full_path);
2419    }
2420
2421  if (dbus_error_is_set (&error))
2422    {
2423      _dbus_warn ("Could not get next file in %s: %s\n",
2424                  _dbus_string_get_const_data (&test_directory), error.message);
2425      dbus_error_free (&error);
2426      goto failed;
2427    }
2428
2429  retval = TRUE;
2430
2431 failed:
2432
2433  if (dir)
2434    _dbus_directory_close (dir);
2435  _dbus_string_free (&test_directory);
2436  _dbus_string_free (&filename);
2437
2438  return retval;
2439}
2440
2441static dbus_bool_t
2442process_test_dirs (const char *test_data_dir)
2443{
2444  DBusString test_directory;
2445  dbus_bool_t retval;
2446
2447  retval = FALSE;
2448
2449  _dbus_string_init_const (&test_directory, test_data_dir);
2450
2451  if (!process_test_subdir (&test_directory, "auth"))
2452    goto failed;
2453
2454  retval = TRUE;
2455
2456 failed:
2457
2458  _dbus_string_free (&test_directory);
2459
2460  return retval;
2461}
2462
2463dbus_bool_t
2464_dbus_auth_test (const char *test_data_dir)
2465{
2466
2467  if (test_data_dir == NULL)
2468    return TRUE;
2469
2470  if (!process_test_dirs (test_data_dir))
2471    return FALSE;
2472
2473  return TRUE;
2474}
2475
2476#endif /* DBUS_BUILD_TESTS */
2477