1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-auth.c Authentication
4 * Copyright (C) 2002 Red Hat Inc.
6 * Licensed under the Academic Free License version 1.2
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "dbus-auth.h"
24 #include "dbus-string.h"
25 #include "dbus-list.h"
26 #include "dbus-internals.h"
28 /* See doc/dbus-sasl-profile.txt */
31 * @defgroup DBusAuth Authentication
32 * @ingroup DBusInternals
33 * @brief DBusAuth object
35 * DBusAuth manages the authentication negotiation when a connection
36 * is first established, and also manage any encryption used over a
39 * The file doc/dbus-sasl-profile.txt documents the network protocol
40 * used for authentication.
44 * @defgroup DBusAuthInternals Authentication implementation details
45 * @ingroup DBusInternals
46 * @brief DBusAuth implementation details
48 * Private details of authentication code.
54 * Processes a command. Returns whether we had enough memory to
55 * complete the operation.
57 typedef dbus_bool_t (* DBusProcessAuthCommandFunction) (DBusAuth *auth,
58 const DBusString *command,
59 const DBusString *args);
64 DBusProcessAuthCommandFunction func;
65 } DBusAuthCommandHandler;
68 * This function processes a block of data received from the peer.
69 * i.e. handles a DATA command.
71 typedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth,
72 const DBusString *data);
75 * This function encodes a block of data from the peer.
77 typedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth,
78 const DBusString *data,
82 * This function decodes a block of data from the peer.
84 typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth,
85 const DBusString *data,
89 * This function is called when the mechanism is abandoned.
91 typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth);
95 const char *mechanism;
96 DBusAuthDataFunction server_data_func;
97 DBusAuthEncodeFunction server_encode_func;
98 DBusAuthDecodeFunction server_decode_func;
99 DBusAuthShutdownFunction server_shutdown_func;
100 DBusAuthDataFunction client_data_func;
101 DBusAuthEncodeFunction client_encode_func;
102 DBusAuthDecodeFunction client_decode_func;
103 DBusAuthShutdownFunction client_shutdown_func;
104 } DBusAuthMechanismHandler;
107 * Internal members of DBusAuth.
111 int refcount; /**< reference count */
113 DBusString incoming; /**< Incoming data buffer */
114 DBusString outgoing; /**< Outgoing data buffer */
116 const DBusAuthCommandHandler *handlers; /**< Handlers for commands */
118 const DBusAuthMechanismHandler *mech; /**< Current auth mechanism */
120 unsigned int needed_memory : 1; /**< We needed memory to continue since last
121 * successful getting something done
123 unsigned int need_disconnect : 1; /**< We've given up, time to disconnect */
124 unsigned int authenticated : 1; /**< We are authenticated */
125 unsigned int authenticated_pending_output : 1; /**< Authenticated once we clear outgoing buffer */
126 unsigned int authenticated_pending_begin : 1; /**< Authenticated once we get BEGIN */
127 unsigned int already_got_mechanisms : 1; /**< Client already got mech list */
134 DBusList *mechs_to_try;
144 static dbus_bool_t process_auth (DBusAuth *auth,
145 const DBusString *command,
146 const DBusString *args);
147 static dbus_bool_t process_cancel (DBusAuth *auth,
148 const DBusString *command,
149 const DBusString *args);
150 static dbus_bool_t process_begin (DBusAuth *auth,
151 const DBusString *command,
152 const DBusString *args);
153 static dbus_bool_t process_data_server (DBusAuth *auth,
154 const DBusString *command,
155 const DBusString *args);
156 static dbus_bool_t process_error_server (DBusAuth *auth,
157 const DBusString *command,
158 const DBusString *args);
159 static dbus_bool_t process_mechanisms (DBusAuth *auth,
160 const DBusString *command,
161 const DBusString *args);
162 static dbus_bool_t process_rejected (DBusAuth *auth,
163 const DBusString *command,
164 const DBusString *args);
165 static dbus_bool_t process_ok (DBusAuth *auth,
166 const DBusString *command,
167 const DBusString *args);
168 static dbus_bool_t process_data_client (DBusAuth *auth,
169 const DBusString *command,
170 const DBusString *args);
171 static dbus_bool_t process_error_client (DBusAuth *auth,
172 const DBusString *command,
173 const DBusString *args);
176 static DBusAuthCommandHandler
177 server_handlers[] = {
178 { "AUTH", process_auth },
179 { "CANCEL", process_cancel },
180 { "BEGIN", process_begin },
181 { "DATA", process_data_server },
182 { "ERROR", process_error_server },
186 static DBusAuthCommandHandler
187 client_handlers[] = {
188 { "MECHANISMS", process_mechanisms },
189 { "REJECTED", process_rejected },
190 { "OK", process_ok },
191 { "DATA", process_data_client },
192 { "ERROR", process_error_client },
197 * @param auth the auth conversation
198 * @returns #TRUE if the conversation is the server side
200 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->handlers == server_handlers)
202 * @param auth the auth conversation
203 * @returns #TRUE if the conversation is the client side
205 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->handlers == client_handlers)
207 * @param auth the auth conversation
208 * @returns auth cast to DBusAuthClient
210 #define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth))
212 * @param auth the auth conversation
213 * @returns auth cast to DBusAuthServer
215 #define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth))
218 _dbus_auth_new (int size)
222 auth = dbus_malloc0 (size);
228 /* note that we don't use the max string length feature,
229 * because you can't use that feature if you're going to
230 * try to recover from out-of-memory (it creates
231 * what looks like unrecoverable inability to alloc
232 * more space in the string). But we do handle
233 * overlong buffers in _dbus_auth_do_work().
236 if (!_dbus_string_init (&auth->incoming, _DBUS_INT_MAX))
242 if (!_dbus_string_init (&auth->outgoing, _DBUS_INT_MAX))
244 _dbus_string_free (&auth->outgoing);
253 get_state (DBusAuth *auth)
255 if (auth->need_disconnect)
256 return DBUS_AUTH_STATE_NEED_DISCONNECT;
257 else if (auth->authenticated)
258 return DBUS_AUTH_STATE_AUTHENTICATED;
259 else if (auth->needed_memory)
260 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
261 else if (_dbus_string_get_length (&auth->outgoing) > 0)
262 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
264 return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
268 shutdown_mech (DBusAuth *auth)
270 /* Cancel any auth */
271 auth->authenticated_pending_begin = FALSE;
272 auth->authenticated = FALSE;
274 if (auth->mech != NULL)
276 if (DBUS_AUTH_IS_CLIENT (auth))
277 (* auth->mech->client_shutdown_func) (auth);
279 (* auth->mech->server_shutdown_func) (auth);
286 handle_server_data_stupid_test_mech (DBusAuth *auth,
287 const DBusString *data)
289 if (!_dbus_string_append (&auth->outgoing,
293 auth->authenticated_pending_begin = TRUE;
299 handle_server_shutdown_stupid_test_mech (DBusAuth *auth)
305 handle_client_data_stupid_test_mech (DBusAuth *auth,
306 const DBusString *data)
313 handle_client_shutdown_stupid_test_mech (DBusAuth *auth)
318 /* the stupid test mech is a base64-encoded string;
319 * all the inefficiency, none of the security!
322 handle_encode_stupid_test_mech (DBusAuth *auth,
323 const DBusString *plaintext,
326 if (!_dbus_string_base64_encode (plaintext, 0, encoded, 0))
333 handle_decode_stupid_test_mech (DBusAuth *auth,
334 const DBusString *encoded,
335 DBusString *plaintext)
337 if (!_dbus_string_base64_decode (encoded, 0, plaintext, 0))
343 /* Put mechanisms here in order of preference.
344 * What I eventually want to have is:
346 * - a mechanism that checks UNIX domain socket credentials
347 * - a simple magic cookie mechanism like X11 or ICE
348 * - mechanisms that chain to Cyrus SASL, so we can use anything it
349 * offers such as Kerberos, X509, whatever.
352 static const DBusAuthMechanismHandler
354 { "DBUS_STUPID_TEST_MECH",
355 handle_server_data_stupid_test_mech,
356 handle_encode_stupid_test_mech,
357 handle_decode_stupid_test_mech,
358 handle_server_shutdown_stupid_test_mech,
359 handle_client_data_stupid_test_mech,
360 handle_encode_stupid_test_mech,
361 handle_decode_stupid_test_mech,
362 handle_client_shutdown_stupid_test_mech },
366 static const DBusAuthMechanismHandler*
367 find_mech (const DBusString *name)
372 while (all_mechanisms[i].mechanism != NULL)
374 if (_dbus_string_equal_c_str (name,
375 all_mechanisms[i].mechanism))
377 return &all_mechanisms[i];
386 send_mechanisms (DBusAuth *auth)
391 if (!_dbus_string_init (&command, _DBUS_INT_MAX))
394 if (!_dbus_string_append (&command,
399 while (all_mechanisms[i].mechanism != NULL)
401 if (!_dbus_string_append (&command,
405 if (!_dbus_string_append (&command,
406 all_mechanisms[i].mechanism))
412 if (!_dbus_string_append (&command, "\r\n"))
415 if (!_dbus_string_copy (&command, 0, &auth->outgoing,
416 _dbus_string_get_length (&auth->outgoing)))
422 _dbus_string_free (&command);
427 process_auth (DBusAuth *auth,
428 const DBusString *command,
429 const DBusString *args)
433 /* We are already using a mechanism, client is on crack */
434 if (!_dbus_string_append (&auth->outgoing,
435 "ERROR \"Sent AUTH while another AUTH in progress\"\r\n"))
440 else if (_dbus_string_get_length (args) == 0)
442 /* No args to the auth, send mechanisms */
443 if (!send_mechanisms (auth))
452 DBusString base64_response;
453 DBusString decoded_response;
455 _dbus_string_find_blank (args, 0, &i);
457 if (!_dbus_string_init (&mech, _DBUS_INT_MAX))
460 if (!_dbus_string_init (&base64_response, _DBUS_INT_MAX))
462 _dbus_string_free (&mech);
466 if (!_dbus_string_init (&decoded_response, _DBUS_INT_MAX))
468 _dbus_string_free (&mech);
469 _dbus_string_free (&base64_response);
473 if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
476 if (!_dbus_string_copy (args, i, &base64_response, 0))
479 if (!_dbus_string_base64_decode (&base64_response, 0,
480 &decoded_response, 0))
483 auth->mech = find_mech (&mech);
484 if (auth->mech != NULL)
486 if (!(* auth->mech->server_data_func) (auth,
492 /* Unsupported mechanism */
493 if (!send_mechanisms (auth))
501 _dbus_string_free (&mech);
502 _dbus_string_free (&base64_response);
503 _dbus_string_free (&decoded_response);
509 process_cancel (DBusAuth *auth,
510 const DBusString *command,
511 const DBusString *args)
513 shutdown_mech (auth);
519 process_begin (DBusAuth *auth,
520 const DBusString *command,
521 const DBusString *args)
523 if (auth->authenticated_pending_begin)
524 auth->authenticated = TRUE;
527 auth->need_disconnect = TRUE; /* client trying to send data before auth,
530 shutdown_mech (auth);
537 process_data_server (DBusAuth *auth,
538 const DBusString *command,
539 const DBusString *args)
541 if (auth->mech != NULL)
545 if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
548 if (!_dbus_string_base64_decode (args, 0, &decoded, 0))
550 _dbus_string_free (&decoded);
554 if (!(* auth->mech->server_data_func) (auth, &decoded))
556 _dbus_string_free (&decoded);
560 _dbus_string_free (&decoded);
564 if (!_dbus_string_append (&auth->outgoing,
565 "ERROR \"Not currently in an auth conversation\"\r\n"))
573 process_error_server (DBusAuth *auth,
574 const DBusString *command,
575 const DBusString *args)
582 get_word (const DBusString *str,
588 _dbus_string_find_blank (str, *start, &i);
592 if (!_dbus_string_copy_len (str, *start, i, word, 0))
602 process_mechanisms (DBusAuth *auth,
603 const DBusString *command,
604 const DBusString *args)
609 if (auth->already_got_mechanisms)
612 len = _dbus_string_get_length (args);
618 const DBusAuthMechanismHandler *mech;
620 if (!_dbus_string_init (&m, _DBUS_INT_MAX))
623 if (!get_word (args, &next, &m))
626 mech = find_mech (&m);
630 /* FIXME right now we try mechanisms in the order
631 * the server lists them; should we do them in
632 * some more deterministic order?
634 * Probably in all_mechanisms order, our order of
635 * preference. Of course when the server is us,
636 * it lists things in that order anyhow.
639 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
645 auth->already_got_mechanisms = TRUE;
650 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
656 process_rejected (DBusAuth *auth,
657 const DBusString *command,
658 const DBusString *args)
660 shutdown_mech (auth);
662 if (!auth->already_got_mechanisms)
664 /* Ask for mechanisms */
665 if (!_dbus_string_append (&auth->outgoing,
669 else if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
671 /* Try next mechanism */
672 const DBusAuthMechanismHandler *mech;
673 DBusString auth_command;
675 mech = DBUS_AUTH_CLIENT (auth)->mechs_to_try->data;
677 if (!_dbus_string_init (&auth_command, _DBUS_INT_MAX))
680 if (!_dbus_string_append (&auth_command,
683 _dbus_string_free (&auth_command);
687 if (!_dbus_string_append (&auth->outgoing,
690 _dbus_string_free (&auth_command);
694 if (!_dbus_string_append (&auth->outgoing,
697 _dbus_string_free (&auth_command);
701 if (!_dbus_string_copy (&auth_command, 0,
703 _dbus_string_get_length (&auth->outgoing)))
705 _dbus_string_free (&auth_command);
709 _dbus_list_pop_first (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
714 auth->need_disconnect = TRUE;
721 process_ok (DBusAuth *auth,
722 const DBusString *command,
723 const DBusString *args)
725 if (!_dbus_string_append (&auth->outgoing,
729 auth->authenticated_pending_output = TRUE;
736 process_data_client (DBusAuth *auth,
737 const DBusString *command,
738 const DBusString *args)
740 if (auth->mech != NULL)
744 if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
747 if (!_dbus_string_base64_decode (args, 0, &decoded, 0))
749 _dbus_string_free (&decoded);
753 if (!(* auth->mech->client_data_func) (auth, &decoded))
755 _dbus_string_free (&decoded);
759 _dbus_string_free (&decoded);
763 if (!_dbus_string_append (&auth->outgoing,
764 "ERROR \"Got DATA when not in an auth exchange\"\r\n"))
772 process_error_client (DBusAuth *auth,
773 const DBusString *command,
774 const DBusString *args)
780 process_unknown (DBusAuth *auth,
781 const DBusString *command,
782 const DBusString *args)
784 if (!_dbus_string_append (&auth->outgoing,
785 "ERROR \"Unknown command\"\r\n"))
791 /* returns whether to call it again right away */
793 process_command (DBusAuth *auth)
804 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
807 if (!_dbus_string_init (&command, _DBUS_INT_MAX))
809 auth->needed_memory = TRUE;
813 if (!_dbus_string_init (&args, _DBUS_INT_MAX))
815 auth->needed_memory = TRUE;
819 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &command, 0))
822 _dbus_string_find_blank (&command, 0, &i);
823 _dbus_string_skip_blank (&command, i, &j);
826 _dbus_string_delete (&command, i, j);
828 if (!_dbus_string_move (&command, i, &args, 0))
832 while (auth->handlers[i].command != NULL)
834 if (_dbus_string_equal_c_str (&command,
835 auth->handlers[i].command))
837 if (!(* auth->handlers[i].func) (auth, &command, &args))
845 if (auth->handlers[i].command == NULL)
847 if (!process_unknown (auth, &command, &args))
851 /* We've succeeded in processing the whole command so drop it out
852 * of the incoming buffer and return TRUE to try another command.
855 _dbus_string_delete (&auth->incoming, 0, eol);
858 _dbus_string_delete (&auth->incoming, 0, 2);
863 _dbus_string_free (&args);
864 _dbus_string_free (&command);
867 auth->needed_memory = TRUE;
869 auth->needed_memory = FALSE;
878 * @addtogroup DBusAuth
883 * Creates a new auth conversation object for the server side.
884 * See doc/dbus-sasl-profile.txt for full details on what
887 * @returns the new object or #NULL if no memory
890 _dbus_auth_server_new (void)
894 auth = _dbus_auth_new (sizeof (DBusAuthServer));
898 auth->handlers = server_handlers;
904 * Creates a new auth conversation object for the client side.
905 * See doc/dbus-sasl-profile.txt for full details on what
908 * @returns the new object or #NULL if no memory
911 _dbus_auth_client_new (void)
915 auth = _dbus_auth_new (sizeof (DBusAuthClient));
919 auth->handlers = client_handlers;
921 /* Request an auth */
922 if (!_dbus_string_append (&auth->outgoing,
923 "AUTH DBUS_STUPID_TEST_MECH\r\n"))
925 _dbus_auth_unref (auth);
933 * Increments the refcount of an auth object.
935 * @param auth the auth conversation
938 _dbus_auth_ref (DBusAuth *auth)
940 _dbus_assert (auth != NULL);
946 * Decrements the refcount of an auth object.
948 * @param auth the auth conversation
951 _dbus_auth_unref (DBusAuth *auth)
953 _dbus_assert (auth != NULL);
954 _dbus_assert (auth->refcount > 0);
957 if (auth->refcount == 0)
959 shutdown_mech (auth);
961 if (DBUS_AUTH_IS_CLIENT (auth))
963 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
966 _dbus_string_free (&auth->incoming);
967 _dbus_string_free (&auth->outgoing);
973 * @param auth the auth conversation object
974 * @returns #TRUE if we're in a final state
976 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->need_disconnect || (auth)->authenticated)
979 * Analyzes buffered input and moves the auth conversation forward,
980 * returning the new state of the auth conversation.
982 * @param auth the auth conversation
983 * @returns the new state
986 _dbus_auth_do_work (DBusAuth *auth)
988 if (DBUS_AUTH_IN_END_STATE (auth))
989 return get_state (auth);
991 auth->needed_memory = FALSE;
993 /* Max amount we'll buffer up before deciding someone's on crack */
994 #define MAX_BUFFER (16 * 1024)
998 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
999 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
1001 auth->need_disconnect = TRUE;
1002 _dbus_verbose ("Disconnecting due to excessive data buffered in auth phase\n");
1006 while (process_command (auth));
1008 return get_state (auth);
1012 * Gets bytes that need to be sent to the
1013 * peer we're conversing with.
1015 * @param auth the auth conversation
1016 * @param str initialized string object to be filled in with bytes to send
1017 * @returns #FALSE if not enough memory to fill in the bytes
1020 _dbus_auth_get_bytes_to_send (DBusAuth *auth,
1023 _dbus_assert (auth != NULL);
1024 _dbus_assert (str != NULL);
1026 if (DBUS_AUTH_IN_END_STATE (auth))
1029 auth->needed_memory = FALSE;
1031 _dbus_string_set_length (str, 0);
1033 if (!_dbus_string_move (&auth->outgoing,
1036 auth->needed_memory = TRUE;
1040 if (auth->authenticated_pending_output)
1041 auth->authenticated = TRUE;
1047 * Stores bytes received from the peer we're conversing with.
1049 * @param auth the auth conversation
1050 * @param str the received bytes.
1051 * @returns #FALSE if not enough memory to store the bytes.
1054 _dbus_auth_bytes_received (DBusAuth *auth,
1055 const DBusString *str)
1057 _dbus_assert (auth != NULL);
1058 _dbus_assert (str != NULL);
1060 if (DBUS_AUTH_IN_END_STATE (auth))
1063 auth->needed_memory = FALSE;
1065 if (!_dbus_string_copy (str, 0,
1067 _dbus_string_get_length (&auth->incoming)))
1069 auth->needed_memory = TRUE;
1073 _dbus_auth_do_work (auth);
1079 * Returns leftover bytes that were not used as part of the auth
1080 * conversation. These bytes will be part of the message stream
1081 * instead. This function may not be called until authentication has
1084 * @param auth the auth conversation
1085 * @param str string to place the unused bytes in
1086 * @returns #FALSE if not enough memory to return the bytes
1089 _dbus_auth_get_unused_bytes (DBusAuth *auth,
1092 if (!DBUS_AUTH_IN_END_STATE (auth))
1095 if (!_dbus_string_move (&auth->incoming,
1103 * Called post-authentication, indicates whether we need to encode
1104 * the message stream with _dbus_auth_encode_data() prior to
1105 * sending it to the peer.
1107 * @param auth the auth conversation
1108 * @returns #TRUE if we need to encode the stream
1111 _dbus_auth_needs_encoding (DBusAuth *auth)
1113 if (!auth->authenticated)
1116 if (auth->mech != NULL)
1118 if (DBUS_AUTH_IS_CLIENT (auth))
1119 return auth->mech->client_encode_func != NULL;
1121 return auth->mech->server_encode_func != NULL;
1128 * Called post-authentication, encodes a block of bytes for sending to
1129 * the peer. If no encoding was negotiated, just copies the bytes
1130 * (you can avoid this by checking _dbus_auth_needs_encoding()).
1132 * @param auth the auth conversation
1133 * @param plaintext the plain text data
1134 * @param encoded initialized string to fill in with encoded data
1135 * @returns #TRUE if we had enough memory and successfully encoded
1138 _dbus_auth_encode_data (DBusAuth *auth,
1139 const DBusString *plaintext,
1140 DBusString *encoded)
1142 if (!auth->authenticated)
1145 if (_dbus_auth_needs_encoding (auth))
1147 if (DBUS_AUTH_IS_CLIENT (auth))
1148 return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
1150 return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
1154 return _dbus_string_copy (plaintext, 0, encoded, 0);
1159 * Called post-authentication, indicates whether we need to decode
1160 * the message stream with _dbus_auth_decode_data() after
1161 * receiving it from the peer.
1163 * @param auth the auth conversation
1164 * @returns #TRUE if we need to encode the stream
1167 _dbus_auth_needs_decoding (DBusAuth *auth)
1169 if (!auth->authenticated)
1172 if (auth->mech != NULL)
1174 if (DBUS_AUTH_IS_CLIENT (auth))
1175 return auth->mech->client_decode_func != NULL;
1177 return auth->mech->server_decode_func != NULL;
1185 * Called post-authentication, decodes a block of bytes received from
1186 * the peer. If no encoding was negotiated, just copies the bytes (you
1187 * can avoid this by checking _dbus_auth_needs_decoding()).
1189 * @param auth the auth conversation
1190 * @param encoded the encoded data
1191 * @param plaintext initialized string to fill in with decoded data
1192 * @returns #TRUE if we had enough memory and successfully decoded
1195 _dbus_auth_decode_data (DBusAuth *auth,
1196 const DBusString *encoded,
1197 DBusString *plaintext)
1199 if (!auth->authenticated)
1202 if (_dbus_auth_needs_decoding (auth))
1204 if (DBUS_AUTH_IS_CLIENT (auth))
1205 return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
1207 return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
1211 return _dbus_string_copy (encoded, 0, plaintext, 0);