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 dbus_bool_t client_try_next_mechanism (DBusAuth *auth);
179 static DBusAuthCommandHandler
180 server_handlers[] = {
181 { "AUTH", process_auth },
182 { "CANCEL", process_cancel },
183 { "BEGIN", process_begin },
184 { "DATA", process_data_server },
185 { "ERROR", process_error_server },
189 static DBusAuthCommandHandler
190 client_handlers[] = {
191 { "MECHANISMS", process_mechanisms },
192 { "REJECTED", process_rejected },
193 { "OK", process_ok },
194 { "DATA", process_data_client },
195 { "ERROR", process_error_client },
200 * @param auth the auth conversation
201 * @returns #TRUE if the conversation is the server side
203 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->handlers == server_handlers)
205 * @param auth the auth conversation
206 * @returns #TRUE if the conversation is the client side
208 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->handlers == client_handlers)
210 * @param auth the auth conversation
211 * @returns auth cast to DBusAuthClient
213 #define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth))
215 * @param auth the auth conversation
216 * @returns auth cast to DBusAuthServer
218 #define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth))
221 _dbus_auth_new (int size)
225 auth = dbus_malloc0 (size);
231 /* note that we don't use the max string length feature,
232 * because you can't use that feature if you're going to
233 * try to recover from out-of-memory (it creates
234 * what looks like unrecoverable inability to alloc
235 * more space in the string). But we do handle
236 * overlong buffers in _dbus_auth_do_work().
239 if (!_dbus_string_init (&auth->incoming, _DBUS_INT_MAX))
245 if (!_dbus_string_init (&auth->outgoing, _DBUS_INT_MAX))
247 _dbus_string_free (&auth->outgoing);
256 get_state (DBusAuth *auth)
258 if (auth->need_disconnect)
259 return DBUS_AUTH_STATE_NEED_DISCONNECT;
260 else if (auth->authenticated)
262 if (_dbus_string_get_length (&auth->incoming) > 0)
263 return DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES;
265 return DBUS_AUTH_STATE_AUTHENTICATED;
267 else if (auth->needed_memory)
268 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
269 else if (_dbus_string_get_length (&auth->outgoing) > 0)
270 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
272 return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
276 shutdown_mech (DBusAuth *auth)
278 /* Cancel any auth */
279 auth->authenticated_pending_begin = FALSE;
280 auth->authenticated = FALSE;
282 if (auth->mech != NULL)
284 _dbus_verbose ("Shutting down mechanism %s\n",
285 auth->mech->mechanism);
287 if (DBUS_AUTH_IS_CLIENT (auth))
288 (* auth->mech->client_shutdown_func) (auth);
290 (* auth->mech->server_shutdown_func) (auth);
297 handle_server_data_stupid_test_mech (DBusAuth *auth,
298 const DBusString *data)
300 if (!_dbus_string_append (&auth->outgoing,
304 auth->authenticated_pending_begin = TRUE;
310 handle_server_shutdown_stupid_test_mech (DBusAuth *auth)
316 handle_client_data_stupid_test_mech (DBusAuth *auth,
317 const DBusString *data)
324 handle_client_shutdown_stupid_test_mech (DBusAuth *auth)
329 /* the stupid test mech is a base64-encoded string;
330 * all the inefficiency, none of the security!
333 handle_encode_stupid_test_mech (DBusAuth *auth,
334 const DBusString *plaintext,
337 if (!_dbus_string_base64_encode (plaintext, 0, encoded,
338 _dbus_string_get_length (encoded)))
345 handle_decode_stupid_test_mech (DBusAuth *auth,
346 const DBusString *encoded,
347 DBusString *plaintext)
349 if (!_dbus_string_base64_decode (encoded, 0, plaintext,
350 _dbus_string_get_length (plaintext)))
356 /* Put mechanisms here in order of preference.
357 * What I eventually want to have is:
359 * - a mechanism that checks UNIX domain socket credentials
360 * - a simple magic cookie mechanism like X11 or ICE
361 * - mechanisms that chain to Cyrus SASL, so we can use anything it
362 * offers such as Kerberos, X509, whatever.
365 static const DBusAuthMechanismHandler
367 { "DBUS_STUPID_TEST_MECH",
368 handle_server_data_stupid_test_mech,
369 handle_encode_stupid_test_mech,
370 handle_decode_stupid_test_mech,
371 handle_server_shutdown_stupid_test_mech,
372 handle_client_data_stupid_test_mech,
373 handle_encode_stupid_test_mech,
374 handle_decode_stupid_test_mech,
375 handle_client_shutdown_stupid_test_mech },
379 static const DBusAuthMechanismHandler*
380 find_mech (const DBusString *name)
385 while (all_mechanisms[i].mechanism != NULL)
387 if (_dbus_string_equal_c_str (name,
388 all_mechanisms[i].mechanism))
390 return &all_mechanisms[i];
399 send_mechanisms (DBusAuth *auth)
404 if (!_dbus_string_init (&command, _DBUS_INT_MAX))
407 if (!_dbus_string_append (&command,
412 while (all_mechanisms[i].mechanism != NULL)
414 if (!_dbus_string_append (&command,
418 if (!_dbus_string_append (&command,
419 all_mechanisms[i].mechanism))
425 if (!_dbus_string_append (&command, "\r\n"))
428 if (!_dbus_string_copy (&command, 0, &auth->outgoing,
429 _dbus_string_get_length (&auth->outgoing)))
435 _dbus_string_free (&command);
440 process_auth (DBusAuth *auth,
441 const DBusString *command,
442 const DBusString *args)
446 /* We are already using a mechanism, client is on crack */
447 if (!_dbus_string_append (&auth->outgoing,
448 "ERROR \"Sent AUTH while another AUTH in progress\"\r\n"))
453 else if (_dbus_string_get_length (args) == 0)
455 /* No args to the auth, send mechanisms */
456 if (!send_mechanisms (auth))
465 DBusString base64_response;
466 DBusString decoded_response;
468 _dbus_string_find_blank (args, 0, &i);
470 if (!_dbus_string_init (&mech, _DBUS_INT_MAX))
473 if (!_dbus_string_init (&base64_response, _DBUS_INT_MAX))
475 _dbus_string_free (&mech);
479 if (!_dbus_string_init (&decoded_response, _DBUS_INT_MAX))
481 _dbus_string_free (&mech);
482 _dbus_string_free (&base64_response);
486 if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
489 if (!_dbus_string_copy (args, i, &base64_response, 0))
492 if (!_dbus_string_base64_decode (&base64_response, 0,
493 &decoded_response, 0))
496 auth->mech = find_mech (&mech);
497 if (auth->mech != NULL)
499 _dbus_verbose ("Trying mechanism %s\n",
500 auth->mech->mechanism);
502 if (!(* auth->mech->server_data_func) (auth,
508 /* Unsupported mechanism */
509 if (!send_mechanisms (auth))
517 _dbus_string_free (&mech);
518 _dbus_string_free (&base64_response);
519 _dbus_string_free (&decoded_response);
525 process_cancel (DBusAuth *auth,
526 const DBusString *command,
527 const DBusString *args)
529 shutdown_mech (auth);
535 process_begin (DBusAuth *auth,
536 const DBusString *command,
537 const DBusString *args)
539 if (auth->authenticated_pending_begin)
540 auth->authenticated = TRUE;
543 auth->need_disconnect = TRUE; /* client trying to send data before auth,
546 shutdown_mech (auth);
553 process_data_server (DBusAuth *auth,
554 const DBusString *command,
555 const DBusString *args)
557 if (auth->mech != NULL)
561 if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
564 if (!_dbus_string_base64_decode (args, 0, &decoded, 0))
566 _dbus_string_free (&decoded);
570 if (!(* auth->mech->server_data_func) (auth, &decoded))
572 _dbus_string_free (&decoded);
576 _dbus_string_free (&decoded);
580 if (!_dbus_string_append (&auth->outgoing,
581 "ERROR \"Not currently in an auth conversation\"\r\n"))
589 process_error_server (DBusAuth *auth,
590 const DBusString *command,
591 const DBusString *args)
597 /* return FALSE if no memory, TRUE if all OK */
599 get_word (const DBusString *str,
605 _dbus_string_skip_blank (str, *start, start);
606 _dbus_string_find_blank (str, *start, &i);
610 if (!_dbus_string_copy_len (str, *start, i, word, 0))
620 process_mechanisms (DBusAuth *auth,
621 const DBusString *command,
622 const DBusString *args)
627 if (auth->already_got_mechanisms)
630 len = _dbus_string_get_length (args);
636 const DBusAuthMechanismHandler *mech;
638 if (!_dbus_string_init (&m, _DBUS_INT_MAX))
641 if (!get_word (args, &next, &m))
644 mech = find_mech (&m);
648 /* FIXME right now we try mechanisms in the order
649 * the server lists them; should we do them in
650 * some more deterministic order?
652 * Probably in all_mechanisms order, our order of
653 * preference. Of course when the server is us,
654 * it lists things in that order anyhow.
657 _dbus_verbose ("Adding mechanism %s to list we will try\n",
660 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
668 _dbus_string_get_const_data (&m, &s);
669 _dbus_verbose ("Server offered mechanism \"%s\" that we don't know how to use\n",
673 _dbus_string_free (&m);
676 auth->already_got_mechanisms = TRUE;
681 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
687 client_try_next_mechanism (DBusAuth *auth)
689 const DBusAuthMechanismHandler *mech;
690 DBusString auth_command;
692 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL)
695 mech = DBUS_AUTH_CLIENT (auth)->mechs_to_try->data;
697 if (!_dbus_string_init (&auth_command, _DBUS_INT_MAX))
700 if (!_dbus_string_append (&auth_command,
703 _dbus_string_free (&auth_command);
707 if (!_dbus_string_append (&auth_command,
710 _dbus_string_free (&auth_command);
714 if (!_dbus_string_append (&auth_command,
717 _dbus_string_free (&auth_command);
721 if (!_dbus_string_copy (&auth_command, 0,
723 _dbus_string_get_length (&auth->outgoing)))
725 _dbus_string_free (&auth_command);
730 _dbus_list_pop_first (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
732 _dbus_verbose ("Trying mechanism %s\n",
733 auth->mech->mechanism);
739 process_rejected (DBusAuth *auth,
740 const DBusString *command,
741 const DBusString *args)
743 shutdown_mech (auth);
745 if (!auth->already_got_mechanisms)
747 /* Ask for mechanisms */
748 if (!_dbus_string_append (&auth->outgoing,
752 else if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
754 client_try_next_mechanism (auth);
759 auth->need_disconnect = TRUE;
766 process_ok (DBusAuth *auth,
767 const DBusString *command,
768 const DBusString *args)
770 if (!_dbus_string_append (&auth->outgoing,
774 auth->authenticated_pending_output = TRUE;
781 process_data_client (DBusAuth *auth,
782 const DBusString *command,
783 const DBusString *args)
785 if (auth->mech != NULL)
789 if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
792 if (!_dbus_string_base64_decode (args, 0, &decoded, 0))
794 _dbus_string_free (&decoded);
798 if (!(* auth->mech->client_data_func) (auth, &decoded))
800 _dbus_string_free (&decoded);
804 _dbus_string_free (&decoded);
808 if (!_dbus_string_append (&auth->outgoing,
809 "ERROR \"Got DATA when not in an auth exchange\"\r\n"))
817 process_error_client (DBusAuth *auth,
818 const DBusString *command,
819 const DBusString *args)
825 process_unknown (DBusAuth *auth,
826 const DBusString *command,
827 const DBusString *args)
829 if (!_dbus_string_append (&auth->outgoing,
830 "ERROR \"Unknown command\"\r\n"))
836 /* returns whether to call it again right away */
838 process_command (DBusAuth *auth)
849 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
852 if (!_dbus_string_init (&command, _DBUS_INT_MAX))
854 auth->needed_memory = TRUE;
858 if (!_dbus_string_init (&args, _DBUS_INT_MAX))
860 auth->needed_memory = TRUE;
864 if (eol > _DBUS_ONE_MEGABYTE)
866 /* This is a giant line, someone is trying to hose us. */
867 if (!_dbus_string_append (&auth->outgoing, "ERROR \"Command too long\"\r\n"))
873 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &command, 0))
876 if (!_dbus_string_validate_ascii (&command, 0,
877 _dbus_string_get_length (&command)))
879 _dbus_verbose ("Command contained non-ASCII chars or embedded nul\n");
880 if (!_dbus_string_append (&auth->outgoing, "ERROR \"Command contained non-ASCII\"\r\n"))
888 _dbus_string_get_const_data (&command, &q);
889 _dbus_verbose ("got command \"%s\"\n", q);
892 _dbus_string_find_blank (&command, 0, &i);
893 _dbus_string_skip_blank (&command, i, &j);
896 _dbus_string_delete (&command, i, j - i);
898 if (!_dbus_string_move (&command, i, &args, 0))
902 while (auth->handlers[i].command != NULL)
904 if (_dbus_string_equal_c_str (&command,
905 auth->handlers[i].command))
907 _dbus_verbose ("Processing auth command %s\n",
908 auth->handlers[i].command);
910 if (!(* auth->handlers[i].func) (auth, &command, &args))
918 if (auth->handlers[i].command == NULL)
920 if (!process_unknown (auth, &command, &args))
926 /* We've succeeded in processing the whole command so drop it out
927 * of the incoming buffer and return TRUE to try another command.
930 _dbus_string_delete (&auth->incoming, 0, eol);
933 _dbus_string_delete (&auth->incoming, 0, 2);
938 _dbus_string_free (&args);
939 _dbus_string_free (&command);
942 auth->needed_memory = TRUE;
944 auth->needed_memory = FALSE;
953 * @addtogroup DBusAuth
958 * Creates a new auth conversation object for the server side.
959 * See doc/dbus-sasl-profile.txt for full details on what
962 * @returns the new object or #NULL if no memory
965 _dbus_auth_server_new (void)
969 auth = _dbus_auth_new (sizeof (DBusAuthServer));
973 auth->handlers = server_handlers;
979 * Creates a new auth conversation object for the client side.
980 * See doc/dbus-sasl-profile.txt for full details on what
983 * @returns the new object or #NULL if no memory
986 _dbus_auth_client_new (void)
990 auth = _dbus_auth_new (sizeof (DBusAuthClient));
994 auth->handlers = client_handlers;
996 /* Add a default mechanism to try */
997 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
998 (void*) &all_mechanisms[0]))
1000 _dbus_auth_unref (auth);
1004 /* Now try the mechanism we just added */
1005 if (!client_try_next_mechanism (auth))
1007 _dbus_auth_unref (auth);
1015 * Increments the refcount of an auth object.
1017 * @param auth the auth conversation
1020 _dbus_auth_ref (DBusAuth *auth)
1022 _dbus_assert (auth != NULL);
1024 auth->refcount += 1;
1028 * Decrements the refcount of an auth object.
1030 * @param auth the auth conversation
1033 _dbus_auth_unref (DBusAuth *auth)
1035 _dbus_assert (auth != NULL);
1036 _dbus_assert (auth->refcount > 0);
1038 auth->refcount -= 1;
1039 if (auth->refcount == 0)
1041 shutdown_mech (auth);
1043 if (DBUS_AUTH_IS_CLIENT (auth))
1045 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
1048 _dbus_string_free (&auth->incoming);
1049 _dbus_string_free (&auth->outgoing);
1055 * @param auth the auth conversation object
1056 * @returns #TRUE if we're in a final state
1058 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->need_disconnect || (auth)->authenticated)
1061 * Analyzes buffered input and moves the auth conversation forward,
1062 * returning the new state of the auth conversation.
1064 * @param auth the auth conversation
1065 * @returns the new state
1068 _dbus_auth_do_work (DBusAuth *auth)
1070 if (DBUS_AUTH_IN_END_STATE (auth))
1071 return get_state (auth);
1073 auth->needed_memory = FALSE;
1075 /* Max amount we'll buffer up before deciding someone's on crack */
1076 #define MAX_BUFFER (16 * 1024)
1080 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
1081 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
1083 auth->need_disconnect = TRUE;
1084 _dbus_verbose ("Disconnecting due to excessive data buffered in auth phase\n");
1088 if (auth->mech == NULL &&
1089 auth->already_got_mechanisms &&
1090 DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL)
1092 auth->need_disconnect = TRUE;
1093 _dbus_verbose ("Disconnecting because we are out of mechanisms to try using\n");
1097 while (process_command (auth));
1099 return get_state (auth);
1103 * Gets bytes that need to be sent to the peer we're conversing with.
1104 * After writing some bytes, _dbus_auth_bytes_sent() must be called
1105 * to notify the auth object that they were written.
1107 * @param auth the auth conversation
1108 * @param str return location for a ref to the buffer to send
1109 * @returns #FALSE if nothing to send
1112 _dbus_auth_get_bytes_to_send (DBusAuth *auth,
1113 const DBusString **str)
1115 _dbus_assert (auth != NULL);
1116 _dbus_assert (str != NULL);
1120 if (DBUS_AUTH_IN_END_STATE (auth))
1123 if (_dbus_string_get_length (&auth->outgoing) == 0)
1126 *str = &auth->outgoing;
1132 * Notifies the auth conversation object that
1133 * the given number of bytes of the outgoing buffer
1134 * have been written out.
1136 * @param auth the auth conversation
1137 * @param bytes_sent number of bytes written out
1140 _dbus_auth_bytes_sent (DBusAuth *auth,
1143 _dbus_string_delete (&auth->outgoing,
1146 if (auth->authenticated_pending_output &&
1147 _dbus_string_get_length (&auth->outgoing) == 0)
1148 auth->authenticated = TRUE;
1152 * Stores bytes received from the peer we're conversing with.
1154 * @param auth the auth conversation
1155 * @param str the received bytes.
1156 * @returns #FALSE if not enough memory to store the bytes.
1159 _dbus_auth_bytes_received (DBusAuth *auth,
1160 const DBusString *str)
1162 _dbus_assert (auth != NULL);
1163 _dbus_assert (str != NULL);
1165 if (DBUS_AUTH_IN_END_STATE (auth))
1168 auth->needed_memory = FALSE;
1170 if (!_dbus_string_copy (str, 0,
1172 _dbus_string_get_length (&auth->incoming)))
1174 auth->needed_memory = TRUE;
1178 _dbus_auth_do_work (auth);
1184 * Returns leftover bytes that were not used as part of the auth
1185 * conversation. These bytes will be part of the message stream
1186 * instead. This function may not be called until authentication has
1189 * @param auth the auth conversation
1190 * @param str string to append the unused bytes to
1191 * @returns #FALSE if not enough memory to return the bytes
1194 _dbus_auth_get_unused_bytes (DBusAuth *auth,
1197 if (!DBUS_AUTH_IN_END_STATE (auth))
1200 if (!_dbus_string_move (&auth->incoming,
1202 _dbus_string_get_length (str)))
1209 * Called post-authentication, indicates whether we need to encode
1210 * the message stream with _dbus_auth_encode_data() prior to
1211 * sending it to the peer.
1213 * @param auth the auth conversation
1214 * @returns #TRUE if we need to encode the stream
1217 _dbus_auth_needs_encoding (DBusAuth *auth)
1219 if (!auth->authenticated)
1222 if (auth->mech != NULL)
1224 if (DBUS_AUTH_IS_CLIENT (auth))
1225 return auth->mech->client_encode_func != NULL;
1227 return auth->mech->server_encode_func != NULL;
1234 * Called post-authentication, encodes a block of bytes for sending to
1235 * the peer. If no encoding was negotiated, just copies the bytes
1236 * (you can avoid this by checking _dbus_auth_needs_encoding()).
1238 * @param auth the auth conversation
1239 * @param plaintext the plain text data
1240 * @param encoded initialized string to where encoded data is appended
1241 * @returns #TRUE if we had enough memory and successfully encoded
1244 _dbus_auth_encode_data (DBusAuth *auth,
1245 const DBusString *plaintext,
1246 DBusString *encoded)
1248 _dbus_assert (plaintext != encoded);
1250 if (!auth->authenticated)
1253 if (_dbus_auth_needs_encoding (auth))
1255 if (DBUS_AUTH_IS_CLIENT (auth))
1256 return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
1258 return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
1262 return _dbus_string_copy (plaintext, 0, encoded,
1263 _dbus_string_get_length (encoded));
1268 * Called post-authentication, indicates whether we need to decode
1269 * the message stream with _dbus_auth_decode_data() after
1270 * receiving it from the peer.
1272 * @param auth the auth conversation
1273 * @returns #TRUE if we need to encode the stream
1276 _dbus_auth_needs_decoding (DBusAuth *auth)
1278 if (!auth->authenticated)
1281 if (auth->mech != NULL)
1283 if (DBUS_AUTH_IS_CLIENT (auth))
1284 return auth->mech->client_decode_func != NULL;
1286 return auth->mech->server_decode_func != NULL;
1294 * Called post-authentication, decodes a block of bytes received from
1295 * the peer. If no encoding was negotiated, just copies the bytes (you
1296 * can avoid this by checking _dbus_auth_needs_decoding()).
1298 * @todo We need to be able to distinguish "out of memory" error
1299 * from "the data is hosed" error.
1301 * @param auth the auth conversation
1302 * @param encoded the encoded data
1303 * @param plaintext initialized string where decoded data is appended
1304 * @returns #TRUE if we had enough memory and successfully decoded
1307 _dbus_auth_decode_data (DBusAuth *auth,
1308 const DBusString *encoded,
1309 DBusString *plaintext)
1311 _dbus_assert (plaintext != encoded);
1313 if (!auth->authenticated)
1316 if (_dbus_auth_needs_decoding (auth))
1318 if (DBUS_AUTH_IS_CLIENT (auth))
1319 return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
1321 return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
1325 return _dbus_string_copy (encoded, 0, plaintext,
1326 _dbus_string_get_length (plaintext));