dbus-auth.c revision 3791dcca16cb46b0ff7305beff75d1aa2645940c
17252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/* -*- mode: C; c-file-style: "gnu" -*- */ 27252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/* dbus-auth.c Authentication 37252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 47252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * Copyright (C) 2002, 2003 Red Hat Inc. 57252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 67252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * Licensed under the Academic Free License version 1.2 77252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 87252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * This program is free software; you can redistribute it and/or modify 97252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * it under the terms of the GNU General Public License as published by 107252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * the Free Software Foundation; either version 2 of the License, or 117252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * (at your option) any later version. 127252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 137252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * This program is distributed in the hope that it will be useful, 14415d2cd7454d93b3727fce9147090a24e4c3ccbaPeter Boström * but WITHOUT ANY WARRANTY; without even the implied warranty of 1571f6f4405c1c5f60097f8d10841378088e78e8b9Zeke Chin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 167252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * GNU General Public License for more details. 177252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 187252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * You should have received a copy of the GNU General Public License 197252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * along with this program; if not, write to the Free Software 207252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 217252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 2271f6f4405c1c5f60097f8d10841378088e78e8b9Zeke Chin */ 2391d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg#include "dbus-auth.h" 2471f6f4405c1c5f60097f8d10841378088e78e8b9Zeke Chin#include "dbus-string.h" 257252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström#include "dbus-list.h" 267252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström#include "dbus-internals.h" 277252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 287252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/* See doc/dbus-sasl-profile.txt */ 297252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 307252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/** 317252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * @defgroup DBusAuth Authentication 327252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * @ingroup DBusInternals 337252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * @brief DBusAuth object 347252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 357252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * DBusAuth manages the authentication negotiation when a connection 367252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * is first established, and also manage any encryption used over a 377252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * connection. 387252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 3971f6f4405c1c5f60097f8d10841378088e78e8b9Zeke Chin * The file doc/dbus-sasl-profile.txt documents the network protocol 4071f6f4405c1c5f60097f8d10841378088e78e8b9Zeke Chin * used for authentication. 417252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 427252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 437252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/** 447252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * @defgroup DBusAuthInternals Authentication implementation details 457252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * @ingroup DBusInternals 467252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * @brief DBusAuth implementation details 477252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 487252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * Private details of authentication code. 497252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * 507252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * @{ 517252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 527252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 537252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/** 547252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * Processes a command. Returns whether we had enough memory to 557252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * complete the operation. 567252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 577252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmtypedef dbus_bool_t (* DBusProcessAuthCommandFunction) (DBusAuth *auth, 587252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const DBusString *command, 597252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const DBusString *args); 607252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 617252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmtypedef struct 627252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström{ 637252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const char *command; 647252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusProcessAuthCommandFunction func; 657252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström} DBusAuthCommandHandler; 667252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 6791d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg/** 687252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * This function appends an initial client response to the given string 697252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 707252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmtypedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth, 717252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusString *response); 727252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 737252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/** 747252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * This function processes a block of data received from the peer. 757252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * i.e. handles a DATA command. 767252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 777252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmtypedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth, 787252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const DBusString *data); 79b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström 80b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström/** 81b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström * This function encodes a block of data from the peer. 827252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 837252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmtypedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth, 847252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const DBusString *data, 857252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusString *encoded); 867252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 877252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/** 887252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * This function decodes a block of data from the peer. 897252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 907252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmtypedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth, 917252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const DBusString *data, 927252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusString *decoded); 9349e196af4060624d620297a6bc017699daa33550Peter Boström 947252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/** 957252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * This function is called when the mechanism is abandoned. 967252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 977252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmtypedef void (* DBusAuthShutdownFunction) (DBusAuth *auth); 987252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 997252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmtypedef struct 1007252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström{ 1017252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const char *mechanism; 1027252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusAuthDataFunction server_data_func; 1037252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusAuthEncodeFunction server_encode_func; 1047252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusAuthDecodeFunction server_decode_func; 1057252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusAuthShutdownFunction server_shutdown_func; 1067252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusInitialResponseFunction client_initial_response_func; 1077252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusAuthDataFunction client_data_func; 1087252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusAuthEncodeFunction client_encode_func; 1097252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusAuthDecodeFunction client_decode_func; 1107252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusAuthShutdownFunction client_shutdown_func; 1117252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström} DBusAuthMechanismHandler; 1127252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 1137252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström/** 1147252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * Internal members of DBusAuth. 1157252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 1167252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boströmstruct DBusAuth 1177252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström{ 1187252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström int refcount; /**< reference count */ 1197252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 1207252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusString incoming; /**< Incoming data buffer */ 1217252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusString outgoing; /**< Outgoing data buffer */ 1227252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 1237252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const DBusAuthCommandHandler *handlers; /**< Handlers for commands */ 1247252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 1257252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström const DBusAuthMechanismHandler *mech; /**< Current auth mechanism */ 1267252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 1277252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusString identity; /**< Current identity we're authorizing 1287252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * as. 1297252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström */ 1307252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 1317252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusCredentials credentials; /**< Credentials, fields may be -1 */ 1327252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 1337252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström DBusCredentials authorized_identity; /**< Credentials that are authorized */ 1347252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 1357252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström unsigned int needed_memory : 1; /**< We needed memory to continue since last 1367252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström * successful getting something done 137796cfaf7f76aa740cc7f4bb2c94f88637e475324perkj */ 138796cfaf7f76aa740cc7f4bb2c94f88637e475324perkj unsigned int need_disconnect : 1; /**< We've given up, time to disconnect */ 139796cfaf7f76aa740cc7f4bb2c94f88637e475324perkj unsigned int authenticated : 1; /**< We are authenticated */ 140796cfaf7f76aa740cc7f4bb2c94f88637e475324perkj unsigned int authenticated_pending_output : 1; /**< Authenticated once we clear outgoing buffer */ 141796cfaf7f76aa740cc7f4bb2c94f88637e475324perkj unsigned int authenticated_pending_begin : 1; /**< Authenticated once we get BEGIN */ 142796cfaf7f76aa740cc7f4bb2c94f88637e475324perkj unsigned int already_got_mechanisms : 1; /**< Client already got mech list */ 143b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */ 144b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström}; 145b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström 146b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boströmtypedef struct 147b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström{ 148b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström DBusAuth base; 1497252a2ba8035c4128917a9558a3e34fc9dbe7c44Peter Boström 150 DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */ 151 152} DBusAuthClient; 153 154typedef struct 155{ 156 DBusAuth base; 157 158 int failures; /**< Number of times client has been rejected */ 159 int max_failures; /**< Number of times we reject before disconnect */ 160 161} DBusAuthServer; 162 163static dbus_bool_t process_auth (DBusAuth *auth, 164 const DBusString *command, 165 const DBusString *args); 166static dbus_bool_t process_cancel (DBusAuth *auth, 167 const DBusString *command, 168 const DBusString *args); 169static dbus_bool_t process_begin (DBusAuth *auth, 170 const DBusString *command, 171 const DBusString *args); 172static dbus_bool_t process_data_server (DBusAuth *auth, 173 const DBusString *command, 174 const DBusString *args); 175static dbus_bool_t process_error_server (DBusAuth *auth, 176 const DBusString *command, 177 const DBusString *args); 178static dbus_bool_t process_rejected (DBusAuth *auth, 179 const DBusString *command, 180 const DBusString *args); 181static dbus_bool_t process_ok (DBusAuth *auth, 182 const DBusString *command, 183 const DBusString *args); 184static dbus_bool_t process_data_client (DBusAuth *auth, 185 const DBusString *command, 186 const DBusString *args); 187static dbus_bool_t process_error_client (DBusAuth *auth, 188 const DBusString *command, 189 const DBusString *args); 190 191 192static dbus_bool_t client_try_next_mechanism (DBusAuth *auth); 193static dbus_bool_t send_rejected (DBusAuth *auth); 194 195static DBusAuthCommandHandler 196server_handlers[] = { 197 { "AUTH", process_auth }, 198 { "CANCEL", process_cancel }, 199 { "BEGIN", process_begin }, 200 { "DATA", process_data_server }, 201 { "ERROR", process_error_server }, 202 { NULL, NULL } 203}; 204 205static DBusAuthCommandHandler 206client_handlers[] = { 207 { "REJECTED", process_rejected }, 208 { "OK", process_ok }, 209 { "DATA", process_data_client }, 210 { "ERROR", process_error_client }, 211 { NULL, NULL } 212}; 213 214/** 215 * @param auth the auth conversation 216 * @returns #TRUE if the conversation is the server side 217 */ 218#define DBUS_AUTH_IS_SERVER(auth) ((auth)->handlers == server_handlers) 219/** 220 * @param auth the auth conversation 221 * @returns #TRUE if the conversation is the client side 222 */ 223#define DBUS_AUTH_IS_CLIENT(auth) ((auth)->handlers == client_handlers) 224/** 225 * @param auth the auth conversation 226 * @returns auth cast to DBusAuthClient 227 */ 228#define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth)) 229/** 230 * @param auth the auth conversation 231 * @returns auth cast to DBusAuthServer 232 */ 233#define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth)) 234 235static DBusAuth* 236_dbus_auth_new (int size) 237{ 238 DBusAuth *auth; 239 240 auth = dbus_malloc0 (size); 241 if (auth == NULL) 242 return NULL; 243 244 auth->refcount = 1; 245 246 auth->credentials.pid = -1; 247 auth->credentials.uid = -1; 248 auth->credentials.gid = -1; 249 250 auth->authorized_identity.pid = -1; 251 auth->authorized_identity.uid = -1; 252 auth->authorized_identity.gid = -1; 253 254 /* note that we don't use the max string length feature, 255 * because you can't use that feature if you're going to 256 * try to recover from out-of-memory (it creates 257 * what looks like unrecoverable inability to alloc 258 * more space in the string). But we do handle 259 * overlong buffers in _dbus_auth_do_work(). 260 */ 261 262 if (!_dbus_string_init (&auth->incoming, _DBUS_INT_MAX)) 263 { 264 dbus_free (auth); 265 return NULL; 266 } 267 268 if (!_dbus_string_init (&auth->outgoing, _DBUS_INT_MAX)) 269 { 270 _dbus_string_free (&auth->incoming); 271 dbus_free (auth); 272 return NULL; 273 } 274 275 if (!_dbus_string_init (&auth->identity, _DBUS_INT_MAX)) 276 { 277 _dbus_string_free (&auth->incoming); 278 _dbus_string_free (&auth->outgoing); 279 dbus_free (auth); 280 return NULL; 281 } 282 283 return auth; 284} 285 286static DBusAuthState 287get_state (DBusAuth *auth) 288{ 289 if (DBUS_AUTH_IS_SERVER (auth) && 290 DBUS_AUTH_SERVER (auth)->failures >= 291 DBUS_AUTH_SERVER (auth)->max_failures) 292 auth->need_disconnect = TRUE; 293 294 if (auth->need_disconnect) 295 return DBUS_AUTH_STATE_NEED_DISCONNECT; 296 else if (auth->authenticated) 297 { 298 if (_dbus_string_get_length (&auth->incoming) > 0) 299 return DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES; 300 else 301 return DBUS_AUTH_STATE_AUTHENTICATED; 302 } 303 else if (auth->needed_memory) 304 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; 305 else if (_dbus_string_get_length (&auth->outgoing) > 0) 306 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; 307 else 308 return DBUS_AUTH_STATE_WAITING_FOR_INPUT; 309} 310 311static void 312shutdown_mech (DBusAuth *auth) 313{ 314 /* Cancel any auth */ 315 auth->authenticated_pending_begin = FALSE; 316 auth->authenticated = FALSE; 317 auth->already_asked_for_initial_response = FALSE; 318 _dbus_string_set_length (&auth->identity, 0); 319 auth->authorized_identity.pid = -1; 320 auth->authorized_identity.uid = -1; 321 auth->authorized_identity.gid = -1; 322 323 if (auth->mech != NULL) 324 { 325 _dbus_verbose ("Shutting down mechanism %s\n", 326 auth->mech->mechanism); 327 328 if (DBUS_AUTH_IS_CLIENT (auth)) 329 (* auth->mech->client_shutdown_func) (auth); 330 else 331 (* auth->mech->server_shutdown_func) (auth); 332 333 auth->mech = NULL; 334 } 335} 336 337static dbus_bool_t 338handle_server_data_stupid_test_mech (DBusAuth *auth, 339 const DBusString *data) 340{ 341 if (!_dbus_string_append (&auth->outgoing, 342 "OK\r\n")) 343 return FALSE; 344 345 auth->authenticated_pending_begin = TRUE; 346 347 return TRUE; 348} 349 350static void 351handle_server_shutdown_stupid_test_mech (DBusAuth *auth) 352{ 353 354} 355 356static dbus_bool_t 357handle_client_data_stupid_test_mech (DBusAuth *auth, 358 const DBusString *data) 359{ 360 361 return TRUE; 362} 363 364static void 365handle_client_shutdown_stupid_test_mech (DBusAuth *auth) 366{ 367 368} 369 370/* the stupid test mech is a base64-encoded string; 371 * all the inefficiency, none of the security! 372 */ 373static dbus_bool_t 374handle_encode_stupid_test_mech (DBusAuth *auth, 375 const DBusString *plaintext, 376 DBusString *encoded) 377{ 378 if (!_dbus_string_base64_encode (plaintext, 0, encoded, 379 _dbus_string_get_length (encoded))) 380 return FALSE; 381 382 return TRUE; 383} 384 385static dbus_bool_t 386handle_decode_stupid_test_mech (DBusAuth *auth, 387 const DBusString *encoded, 388 DBusString *plaintext) 389{ 390 if (!_dbus_string_base64_decode (encoded, 0, plaintext, 391 _dbus_string_get_length (plaintext))) 392 return FALSE; 393 394 return TRUE; 395} 396 397static dbus_bool_t 398handle_server_data_external_mech (DBusAuth *auth, 399 const DBusString *data) 400{ 401 DBusCredentials desired_identity; 402 403 if (auth->credentials.uid < 0) 404 { 405 _dbus_verbose ("no credentials, mechanism EXTERNAL can't authenticate\n"); 406 return send_rejected (auth); 407 } 408 409 if (_dbus_string_get_length (data) > 0) 410 { 411 if (_dbus_string_get_length (&auth->identity) > 0) 412 { 413 /* Tried to send two auth identities, wtf */ 414 return send_rejected (auth); 415 } 416 else 417 { 418 /* this is our auth identity */ 419 if (!_dbus_string_copy (data, 0, &auth->identity, 0)) 420 return FALSE; 421 } 422 } 423 424 /* Poke client for an auth identity, if none given */ 425 if (_dbus_string_get_length (&auth->identity) == 0 && 426 !auth->already_asked_for_initial_response) 427 { 428 if (_dbus_string_append (&auth->outgoing, 429 "DATA\r\n")) 430 { 431 _dbus_verbose ("sending empty challenge asking client for auth identity\n"); 432 auth->already_asked_for_initial_response = TRUE; 433 return TRUE; 434 } 435 else 436 return FALSE; 437 } 438 439 desired_identity.pid = -1; 440 desired_identity.uid = -1; 441 desired_identity.gid = -1; 442 443 /* If auth->identity is still empty here, then client 444 * responded with an empty string after we poked it for 445 * an initial response. This means to try to auth the 446 * identity provided in the credentials. 447 */ 448 if (_dbus_string_get_length (&auth->identity) == 0) 449 { 450 desired_identity.uid = auth->credentials.uid; 451 } 452 else 453 { 454 if (!_dbus_credentials_from_uid_string (&auth->identity, 455 &desired_identity)) 456 return send_rejected (auth); 457 } 458 459 if (desired_identity.uid < 0) 460 { 461 _dbus_verbose ("desired UID %d is no good\n", desired_identity.uid); 462 return send_rejected (auth); 463 } 464 465 if (_dbus_credentials_match (&auth->credentials, 466 &desired_identity)) 467 { 468 /* client has authenticated */ 469 _dbus_verbose ("authenticated client with UID %d matching socket credentials UID %d\n", 470 desired_identity.uid, 471 auth->credentials.uid); 472 473 if (!_dbus_string_append (&auth->outgoing, 474 "OK\r\n")) 475 return FALSE; 476 477 auth->authorized_identity.uid = desired_identity.uid; 478 479 auth->authenticated_pending_begin = TRUE; 480 481 return TRUE; 482 } 483 else 484 { 485 return send_rejected (auth); 486 } 487} 488 489static void 490handle_server_shutdown_external_mech (DBusAuth *auth) 491{ 492 493} 494 495static dbus_bool_t 496handle_client_initial_response_external_mech (DBusAuth *auth, 497 DBusString *response) 498{ 499 /* We always append our UID as an initial response, so the server 500 * doesn't have to send back an empty challenge to check whether we 501 * want to specify an identity. i.e. this avoids a round trip that 502 * the spec for the EXTERNAL mechanism otherwise requires. 503 */ 504 DBusString plaintext; 505 506 if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX)) 507 return FALSE; 508 509 if (!_dbus_string_append_our_uid (&plaintext)) 510 goto failed; 511 512 if (!_dbus_string_base64_encode (&plaintext, 0, 513 response, 514 _dbus_string_get_length (response))) 515 goto failed; 516 517 _dbus_string_free (&plaintext); 518 519 return TRUE; 520 521 failed: 522 _dbus_string_free (&plaintext); 523 return FALSE; 524} 525 526static dbus_bool_t 527handle_client_data_external_mech (DBusAuth *auth, 528 const DBusString *data) 529{ 530 531 return TRUE; 532} 533 534static void 535handle_client_shutdown_external_mech (DBusAuth *auth) 536{ 537 538} 539 540/* Put mechanisms here in order of preference. 541 * What I eventually want to have is: 542 * 543 * - a mechanism that checks UNIX domain socket credentials 544 * - a simple magic cookie mechanism like X11 or ICE 545 * - mechanisms that chain to Cyrus SASL, so we can use anything it 546 * offers such as Kerberos, X509, whatever. 547 * 548 */ 549static const DBusAuthMechanismHandler 550all_mechanisms[] = { 551 { "EXTERNAL", 552 handle_server_data_external_mech, 553 NULL, NULL, 554 handle_server_shutdown_external_mech, 555 handle_client_initial_response_external_mech, 556 handle_client_data_external_mech, 557 NULL, NULL, 558 handle_client_shutdown_external_mech }, 559 /* Obviously this has to die for production use */ 560 { "DBUS_STUPID_TEST_MECH", 561 handle_server_data_stupid_test_mech, 562 handle_encode_stupid_test_mech, 563 handle_decode_stupid_test_mech, 564 handle_server_shutdown_stupid_test_mech, 565 NULL, 566 handle_client_data_stupid_test_mech, 567 handle_encode_stupid_test_mech, 568 handle_decode_stupid_test_mech, 569 handle_client_shutdown_stupid_test_mech }, 570 { NULL, NULL } 571}; 572 573static const DBusAuthMechanismHandler* 574find_mech (const DBusString *name) 575{ 576 int i; 577 578 i = 0; 579 while (all_mechanisms[i].mechanism != NULL) 580 { 581 if (_dbus_string_equal_c_str (name, 582 all_mechanisms[i].mechanism)) 583 584 return &all_mechanisms[i]; 585 586 ++i; 587 } 588 589 return NULL; 590} 591 592static dbus_bool_t 593send_rejected (DBusAuth *auth) 594{ 595 DBusString command; 596 DBusAuthServer *server_auth; 597 int i; 598 599 if (!_dbus_string_init (&command, _DBUS_INT_MAX)) 600 return FALSE; 601 602 if (!_dbus_string_append (&command, 603 "REJECTED")) 604 goto nomem; 605 606 i = 0; 607 while (all_mechanisms[i].mechanism != NULL) 608 { 609 if (!_dbus_string_append (&command, 610 " ")) 611 goto nomem; 612 613 if (!_dbus_string_append (&command, 614 all_mechanisms[i].mechanism)) 615 goto nomem; 616 617 ++i; 618 } 619 620 if (!_dbus_string_append (&command, "\r\n")) 621 goto nomem; 622 623 if (!_dbus_string_copy (&command, 0, &auth->outgoing, 624 _dbus_string_get_length (&auth->outgoing))) 625 goto nomem; 626 627 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 628 server_auth = DBUS_AUTH_SERVER (auth); 629 server_auth->failures += 1; 630 631 return TRUE; 632 633 nomem: 634 _dbus_string_free (&command); 635 return FALSE; 636} 637 638static dbus_bool_t 639process_auth (DBusAuth *auth, 640 const DBusString *command, 641 const DBusString *args) 642{ 643 if (auth->mech) 644 { 645 /* We are already using a mechanism, client is on crack */ 646 if (!_dbus_string_append (&auth->outgoing, 647 "ERROR \"Sent AUTH while another AUTH in progress\"\r\n")) 648 return FALSE; 649 650 return TRUE; 651 } 652 else if (_dbus_string_get_length (args) == 0) 653 { 654 /* No args to the auth, send mechanisms */ 655 if (!send_rejected (auth)) 656 return FALSE; 657 658 return TRUE; 659 } 660 else 661 { 662 int i; 663 DBusString mech; 664 DBusString base64_response; 665 DBusString decoded_response; 666 667 _dbus_string_find_blank (args, 0, &i); 668 669 if (!_dbus_string_init (&mech, _DBUS_INT_MAX)) 670 return FALSE; 671 672 if (!_dbus_string_init (&base64_response, _DBUS_INT_MAX)) 673 { 674 _dbus_string_free (&mech); 675 return FALSE; 676 } 677 678 if (!_dbus_string_init (&decoded_response, _DBUS_INT_MAX)) 679 { 680 _dbus_string_free (&mech); 681 _dbus_string_free (&base64_response); 682 return FALSE; 683 } 684 685 if (!_dbus_string_copy_len (args, 0, i, &mech, 0)) 686 goto failed; 687 688 if (!_dbus_string_copy (args, i, &base64_response, 0)) 689 goto failed; 690 691 if (!_dbus_string_base64_decode (&base64_response, 0, 692 &decoded_response, 0)) 693 goto failed; 694 695 auth->mech = find_mech (&mech); 696 if (auth->mech != NULL) 697 { 698 _dbus_verbose ("Trying mechanism %s with initial response of %d bytes\n", 699 auth->mech->mechanism, 700 _dbus_string_get_length (&decoded_response)); 701 702 if (!(* auth->mech->server_data_func) (auth, 703 &decoded_response)) 704 goto failed; 705 } 706 else 707 { 708 /* Unsupported mechanism */ 709 if (!send_rejected (auth)) 710 return FALSE; 711 } 712 713 _dbus_string_free (&mech); 714 _dbus_string_free (&base64_response); 715 _dbus_string_free (&decoded_response); 716 717 return TRUE; 718 719 failed: 720 auth->mech = NULL; 721 _dbus_string_free (&mech); 722 _dbus_string_free (&base64_response); 723 _dbus_string_free (&decoded_response); 724 return FALSE; 725 } 726} 727 728static dbus_bool_t 729process_cancel (DBusAuth *auth, 730 const DBusString *command, 731 const DBusString *args) 732{ 733 shutdown_mech (auth); 734 735 return TRUE; 736} 737 738static dbus_bool_t 739process_begin (DBusAuth *auth, 740 const DBusString *command, 741 const DBusString *args) 742{ 743 if (auth->authenticated_pending_begin) 744 auth->authenticated = TRUE; 745 else 746 { 747 auth->need_disconnect = TRUE; /* client trying to send data before auth, 748 * kick it 749 */ 750 shutdown_mech (auth); 751 } 752 753 return TRUE; 754} 755 756static dbus_bool_t 757process_data_server (DBusAuth *auth, 758 const DBusString *command, 759 const DBusString *args) 760{ 761 if (auth->mech != NULL) 762 { 763 DBusString decoded; 764 765 if (!_dbus_string_init (&decoded, _DBUS_INT_MAX)) 766 return FALSE; 767 768 if (!_dbus_string_base64_decode (args, 0, &decoded, 0)) 769 { 770 _dbus_string_free (&decoded); 771 return FALSE; 772 } 773 774 if (!(* auth->mech->server_data_func) (auth, &decoded)) 775 { 776 _dbus_string_free (&decoded); 777 return FALSE; 778 } 779 780 _dbus_string_free (&decoded); 781 } 782 else 783 { 784 if (!_dbus_string_append (&auth->outgoing, 785 "ERROR \"Not currently in an auth conversation\"\r\n")) 786 return FALSE; 787 } 788 789 return TRUE; 790} 791 792static dbus_bool_t 793process_error_server (DBusAuth *auth, 794 const DBusString *command, 795 const DBusString *args) 796{ 797 798 return TRUE; 799} 800 801/* return FALSE if no memory, TRUE if all OK */ 802static dbus_bool_t 803get_word (const DBusString *str, 804 int *start, 805 DBusString *word) 806{ 807 int i; 808 809 _dbus_string_skip_blank (str, *start, start); 810 _dbus_string_find_blank (str, *start, &i); 811 812 if (i > *start) 813 { 814 if (!_dbus_string_copy_len (str, *start, i, word, 0)) 815 return FALSE; 816 817 *start = i; 818 } 819 820 return TRUE; 821} 822 823static dbus_bool_t 824record_mechanisms (DBusAuth *auth, 825 const DBusString *command, 826 const DBusString *args) 827{ 828 int next; 829 int len; 830 831 if (auth->already_got_mechanisms) 832 return TRUE; 833 834 len = _dbus_string_get_length (args); 835 836 next = 0; 837 while (next < len) 838 { 839 DBusString m; 840 const DBusAuthMechanismHandler *mech; 841 842 if (!_dbus_string_init (&m, _DBUS_INT_MAX)) 843 goto nomem; 844 845 if (!get_word (args, &next, &m)) 846 goto nomem; 847 848 mech = find_mech (&m); 849 850 if (mech != NULL) 851 { 852 /* FIXME right now we try mechanisms in the order 853 * the server lists them; should we do them in 854 * some more deterministic order? 855 * 856 * Probably in all_mechanisms order, our order of 857 * preference. Of course when the server is us, 858 * it lists things in that order anyhow. 859 */ 860 861 _dbus_verbose ("Adding mechanism %s to list we will try\n", 862 mech->mechanism); 863 864 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, 865 (void*) mech)) 866 goto nomem; 867 } 868 else 869 { 870 const char *s; 871 872 _dbus_string_get_const_data (&m, &s); 873 _dbus_verbose ("Server offered mechanism \"%s\" that we don't know how to use\n", 874 s); 875 } 876 877 _dbus_string_free (&m); 878 } 879 880 auth->already_got_mechanisms = TRUE; 881 882 return TRUE; 883 884 nomem: 885 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 886 887 return FALSE; 888} 889 890static dbus_bool_t 891client_try_next_mechanism (DBusAuth *auth) 892{ 893 const DBusAuthMechanismHandler *mech; 894 DBusString auth_command; 895 896 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL) 897 return FALSE; 898 899 mech = DBUS_AUTH_CLIENT (auth)->mechs_to_try->data; 900 901 if (!_dbus_string_init (&auth_command, _DBUS_INT_MAX)) 902 return FALSE; 903 904 if (!_dbus_string_append (&auth_command, 905 "AUTH ")) 906 { 907 _dbus_string_free (&auth_command); 908 return FALSE; 909 } 910 911 if (!_dbus_string_append (&auth_command, 912 mech->mechanism)) 913 { 914 _dbus_string_free (&auth_command); 915 return FALSE; 916 } 917 918 if (mech->client_initial_response_func != NULL) 919 { 920 if (!_dbus_string_append (&auth_command, " ")) 921 { 922 _dbus_string_free (&auth_command); 923 return FALSE; 924 } 925 926 if (!(* mech->client_initial_response_func) (auth, &auth_command)) 927 { 928 _dbus_string_free (&auth_command); 929 return FALSE; 930 } 931 } 932 933 if (!_dbus_string_append (&auth_command, 934 "\r\n")) 935 { 936 _dbus_string_free (&auth_command); 937 return FALSE; 938 } 939 940 if (!_dbus_string_copy (&auth_command, 0, 941 &auth->outgoing, 942 _dbus_string_get_length (&auth->outgoing))) 943 { 944 _dbus_string_free (&auth_command); 945 return FALSE; 946 } 947 948 auth->mech = mech; 949 _dbus_list_pop_first (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 950 951 _dbus_verbose ("Trying mechanism %s\n", 952 auth->mech->mechanism); 953 954 return TRUE; 955} 956 957static dbus_bool_t 958process_rejected (DBusAuth *auth, 959 const DBusString *command, 960 const DBusString *args) 961{ 962 shutdown_mech (auth); 963 964 if (!auth->already_got_mechanisms) 965 { 966 if (!record_mechanisms (auth, command, args)) 967 return FALSE; 968 } 969 970 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) 971 { 972 client_try_next_mechanism (auth); 973 } 974 else 975 { 976 /* Give up */ 977 auth->need_disconnect = TRUE; 978 } 979 980 return TRUE; 981} 982 983static dbus_bool_t 984process_ok (DBusAuth *auth, 985 const DBusString *command, 986 const DBusString *args) 987{ 988 if (!_dbus_string_append (&auth->outgoing, 989 "BEGIN\r\n")) 990 return FALSE; 991 992 auth->authenticated_pending_output = TRUE; 993 994 return TRUE; 995} 996 997 998static dbus_bool_t 999process_data_client (DBusAuth *auth, 1000 const DBusString *command, 1001 const DBusString *args) 1002{ 1003 if (auth->mech != NULL) 1004 { 1005 DBusString decoded; 1006 1007 if (!_dbus_string_init (&decoded, _DBUS_INT_MAX)) 1008 return FALSE; 1009 1010 if (!_dbus_string_base64_decode (args, 0, &decoded, 0)) 1011 { 1012 _dbus_string_free (&decoded); 1013 return FALSE; 1014 } 1015 1016 if (!(* auth->mech->client_data_func) (auth, &decoded)) 1017 { 1018 _dbus_string_free (&decoded); 1019 return FALSE; 1020 } 1021 1022 _dbus_string_free (&decoded); 1023 } 1024 else 1025 { 1026 if (!_dbus_string_append (&auth->outgoing, 1027 "ERROR \"Got DATA when not in an auth exchange\"\r\n")) 1028 return FALSE; 1029 } 1030 1031 return TRUE; 1032} 1033 1034static dbus_bool_t 1035process_error_client (DBusAuth *auth, 1036 const DBusString *command, 1037 const DBusString *args) 1038{ 1039 return TRUE; 1040} 1041 1042static dbus_bool_t 1043process_unknown (DBusAuth *auth, 1044 const DBusString *command, 1045 const DBusString *args) 1046{ 1047 if (!_dbus_string_append (&auth->outgoing, 1048 "ERROR \"Unknown command\"\r\n")) 1049 return FALSE; 1050 1051 return TRUE; 1052} 1053 1054/* returns whether to call it again right away */ 1055static dbus_bool_t 1056process_command (DBusAuth *auth) 1057{ 1058 DBusString command; 1059 DBusString args; 1060 int eol; 1061 int i, j; 1062 dbus_bool_t retval; 1063 1064 retval = FALSE; 1065 1066 eol = 0; 1067 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol)) 1068 return FALSE; 1069 1070 if (!_dbus_string_init (&command, _DBUS_INT_MAX)) 1071 { 1072 auth->needed_memory = TRUE; 1073 return FALSE; 1074 } 1075 1076 if (!_dbus_string_init (&args, _DBUS_INT_MAX)) 1077 { 1078 auth->needed_memory = TRUE; 1079 return FALSE; 1080 } 1081 1082 if (eol > _DBUS_ONE_MEGABYTE) 1083 { 1084 /* This is a giant line, someone is trying to hose us. */ 1085 if (!_dbus_string_append (&auth->outgoing, "ERROR \"Command too long\"\r\n")) 1086 goto out; 1087 else 1088 goto next_command; 1089 } 1090 1091 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &command, 0)) 1092 goto out; 1093 1094 if (!_dbus_string_validate_ascii (&command, 0, 1095 _dbus_string_get_length (&command))) 1096 { 1097 _dbus_verbose ("Command contained non-ASCII chars or embedded nul\n"); 1098 if (!_dbus_string_append (&auth->outgoing, "ERROR \"Command contained non-ASCII\"\r\n")) 1099 goto out; 1100 else 1101 goto next_command; 1102 } 1103 1104 { 1105 const char *q; 1106 _dbus_string_get_const_data (&command, &q); 1107 _dbus_verbose ("got command \"%s\"\n", q); 1108 } 1109 1110 _dbus_string_find_blank (&command, 0, &i); 1111 _dbus_string_skip_blank (&command, i, &j); 1112 1113 if (j > i) 1114 _dbus_string_delete (&command, i, j - i); 1115 1116 if (!_dbus_string_move (&command, i, &args, 0)) 1117 goto out; 1118 1119 i = 0; 1120 while (auth->handlers[i].command != NULL) 1121 { 1122 if (_dbus_string_equal_c_str (&command, 1123 auth->handlers[i].command)) 1124 { 1125 _dbus_verbose ("Processing auth command %s\n", 1126 auth->handlers[i].command); 1127 1128 if (!(* auth->handlers[i].func) (auth, &command, &args)) 1129 goto out; 1130 1131 break; 1132 } 1133 ++i; 1134 } 1135 1136 if (auth->handlers[i].command == NULL) 1137 { 1138 if (!process_unknown (auth, &command, &args)) 1139 goto out; 1140 } 1141 1142 next_command: 1143 1144 /* We've succeeded in processing the whole command so drop it out 1145 * of the incoming buffer and return TRUE to try another command. 1146 */ 1147 1148 _dbus_string_delete (&auth->incoming, 0, eol); 1149 1150 /* kill the \r\n */ 1151 _dbus_string_delete (&auth->incoming, 0, 2); 1152 1153 retval = TRUE; 1154 1155 out: 1156 _dbus_string_free (&args); 1157 _dbus_string_free (&command); 1158 1159 if (!retval) 1160 auth->needed_memory = TRUE; 1161 else 1162 auth->needed_memory = FALSE; 1163 1164 return retval; 1165} 1166 1167 1168/** @} */ 1169 1170/** 1171 * @addtogroup DBusAuth 1172 * @{ 1173 */ 1174 1175/** 1176 * Creates a new auth conversation object for the server side. 1177 * See doc/dbus-sasl-profile.txt for full details on what 1178 * this object does. 1179 * 1180 * @returns the new object or #NULL if no memory 1181 */ 1182DBusAuth* 1183_dbus_auth_server_new (void) 1184{ 1185 DBusAuth *auth; 1186 DBusAuthServer *server_auth; 1187 1188 auth = _dbus_auth_new (sizeof (DBusAuthServer)); 1189 if (auth == NULL) 1190 return NULL; 1191 1192 auth->handlers = server_handlers; 1193 1194 server_auth = DBUS_AUTH_SERVER (auth); 1195 1196 /* perhaps this should be per-mechanism with a lower 1197 * max 1198 */ 1199 server_auth->failures = 0; 1200 server_auth->max_failures = 6; 1201 1202 return auth; 1203} 1204 1205/** 1206 * Creates a new auth conversation object for the client side. 1207 * See doc/dbus-sasl-profile.txt for full details on what 1208 * this object does. 1209 * 1210 * @returns the new object or #NULL if no memory 1211 */ 1212DBusAuth* 1213_dbus_auth_client_new (void) 1214{ 1215 DBusAuth *auth; 1216 1217 auth = _dbus_auth_new (sizeof (DBusAuthClient)); 1218 if (auth == NULL) 1219 return NULL; 1220 1221 auth->handlers = client_handlers; 1222 1223 /* Add a default mechanism to try */ 1224 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, 1225 (void*) &all_mechanisms[0])) 1226 { 1227 _dbus_auth_unref (auth); 1228 return NULL; 1229 } 1230 1231 /* Now try the mechanism we just added */ 1232 if (!client_try_next_mechanism (auth)) 1233 { 1234 _dbus_auth_unref (auth); 1235 return NULL; 1236 } 1237 1238 return auth; 1239} 1240 1241/** 1242 * Increments the refcount of an auth object. 1243 * 1244 * @param auth the auth conversation 1245 */ 1246void 1247_dbus_auth_ref (DBusAuth *auth) 1248{ 1249 _dbus_assert (auth != NULL); 1250 1251 auth->refcount += 1; 1252} 1253 1254/** 1255 * Decrements the refcount of an auth object. 1256 * 1257 * @param auth the auth conversation 1258 */ 1259void 1260_dbus_auth_unref (DBusAuth *auth) 1261{ 1262 _dbus_assert (auth != NULL); 1263 _dbus_assert (auth->refcount > 0); 1264 1265 auth->refcount -= 1; 1266 if (auth->refcount == 0) 1267 { 1268 shutdown_mech (auth); 1269 1270 if (DBUS_AUTH_IS_CLIENT (auth)) 1271 { 1272 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 1273 } 1274 1275 _dbus_string_free (&auth->identity); 1276 _dbus_string_free (&auth->incoming); 1277 _dbus_string_free (&auth->outgoing); 1278 dbus_free (auth); 1279 } 1280} 1281 1282/** 1283 * @param auth the auth conversation object 1284 * @returns #TRUE if we're in a final state 1285 */ 1286#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->need_disconnect || (auth)->authenticated) 1287 1288/** 1289 * Analyzes buffered input and moves the auth conversation forward, 1290 * returning the new state of the auth conversation. 1291 * 1292 * @param auth the auth conversation 1293 * @returns the new state 1294 */ 1295DBusAuthState 1296_dbus_auth_do_work (DBusAuth *auth) 1297{ 1298 if (DBUS_AUTH_IN_END_STATE (auth)) 1299 return get_state (auth); 1300 1301 auth->needed_memory = FALSE; 1302 1303 /* Max amount we'll buffer up before deciding someone's on crack */ 1304#define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE) 1305 1306 do 1307 { 1308 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER || 1309 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER) 1310 { 1311 auth->need_disconnect = TRUE; 1312 _dbus_verbose ("Disconnecting due to excessive data buffered in auth phase\n"); 1313 break; 1314 } 1315 1316 if (auth->mech == NULL && 1317 auth->already_got_mechanisms && 1318 DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL) 1319 { 1320 auth->need_disconnect = TRUE; 1321 _dbus_verbose ("Disconnecting because we are out of mechanisms to try using\n"); 1322 break; 1323 } 1324 } 1325 while (process_command (auth)); 1326 1327 return get_state (auth); 1328} 1329 1330/** 1331 * Gets bytes that need to be sent to the peer we're conversing with. 1332 * After writing some bytes, _dbus_auth_bytes_sent() must be called 1333 * to notify the auth object that they were written. 1334 * 1335 * @param auth the auth conversation 1336 * @param str return location for a ref to the buffer to send 1337 * @returns #FALSE if nothing to send 1338 */ 1339dbus_bool_t 1340_dbus_auth_get_bytes_to_send (DBusAuth *auth, 1341 const DBusString **str) 1342{ 1343 _dbus_assert (auth != NULL); 1344 _dbus_assert (str != NULL); 1345 1346 *str = NULL; 1347 1348 if (DBUS_AUTH_IN_END_STATE (auth)) 1349 return FALSE; 1350 1351 if (_dbus_string_get_length (&auth->outgoing) == 0) 1352 return FALSE; 1353 1354 *str = &auth->outgoing; 1355 1356 return TRUE; 1357} 1358 1359/** 1360 * Notifies the auth conversation object that 1361 * the given number of bytes of the outgoing buffer 1362 * have been written out. 1363 * 1364 * @param auth the auth conversation 1365 * @param bytes_sent number of bytes written out 1366 */ 1367void 1368_dbus_auth_bytes_sent (DBusAuth *auth, 1369 int bytes_sent) 1370{ 1371 _dbus_string_delete (&auth->outgoing, 1372 0, bytes_sent); 1373 1374 if (auth->authenticated_pending_output && 1375 _dbus_string_get_length (&auth->outgoing) == 0) 1376 auth->authenticated = TRUE; 1377} 1378 1379/** 1380 * Stores bytes received from the peer we're conversing with. 1381 * 1382 * @param auth the auth conversation 1383 * @param str the received bytes. 1384 * @returns #FALSE if not enough memory to store the bytes. 1385 */ 1386dbus_bool_t 1387_dbus_auth_bytes_received (DBusAuth *auth, 1388 const DBusString *str) 1389{ 1390 _dbus_assert (auth != NULL); 1391 _dbus_assert (str != NULL); 1392 1393 if (DBUS_AUTH_IN_END_STATE (auth)) 1394 return FALSE; 1395 1396 auth->needed_memory = FALSE; 1397 1398 if (!_dbus_string_copy (str, 0, 1399 &auth->incoming, 1400 _dbus_string_get_length (&auth->incoming))) 1401 { 1402 auth->needed_memory = TRUE; 1403 return FALSE; 1404 } 1405 1406 _dbus_auth_do_work (auth); 1407 1408 return TRUE; 1409} 1410 1411/** 1412 * Returns leftover bytes that were not used as part of the auth 1413 * conversation. These bytes will be part of the message stream 1414 * instead. This function may not be called until authentication has 1415 * succeeded. 1416 * 1417 * @param auth the auth conversation 1418 * @param str string to append the unused bytes to 1419 * @returns #FALSE if not enough memory to return the bytes 1420 */ 1421dbus_bool_t 1422_dbus_auth_get_unused_bytes (DBusAuth *auth, 1423 DBusString *str) 1424{ 1425 if (!DBUS_AUTH_IN_END_STATE (auth)) 1426 return FALSE; 1427 1428 if (!_dbus_string_move (&auth->incoming, 1429 0, str, 1430 _dbus_string_get_length (str))) 1431 return FALSE; 1432 1433 return TRUE; 1434} 1435 1436/** 1437 * Called post-authentication, indicates whether we need to encode 1438 * the message stream with _dbus_auth_encode_data() prior to 1439 * sending it to the peer. 1440 * 1441 * @param auth the auth conversation 1442 * @returns #TRUE if we need to encode the stream 1443 */ 1444dbus_bool_t 1445_dbus_auth_needs_encoding (DBusAuth *auth) 1446{ 1447 if (!auth->authenticated) 1448 return FALSE; 1449 1450 if (auth->mech != NULL) 1451 { 1452 if (DBUS_AUTH_IS_CLIENT (auth)) 1453 return auth->mech->client_encode_func != NULL; 1454 else 1455 return auth->mech->server_encode_func != NULL; 1456 } 1457 else 1458 return FALSE; 1459} 1460 1461/** 1462 * Called post-authentication, encodes a block of bytes for sending to 1463 * the peer. If no encoding was negotiated, just copies the bytes 1464 * (you can avoid this by checking _dbus_auth_needs_encoding()). 1465 * 1466 * @param auth the auth conversation 1467 * @param plaintext the plain text data 1468 * @param encoded initialized string to where encoded data is appended 1469 * @returns #TRUE if we had enough memory and successfully encoded 1470 */ 1471dbus_bool_t 1472_dbus_auth_encode_data (DBusAuth *auth, 1473 const DBusString *plaintext, 1474 DBusString *encoded) 1475{ 1476 _dbus_assert (plaintext != encoded); 1477 1478 if (!auth->authenticated) 1479 return FALSE; 1480 1481 if (_dbus_auth_needs_encoding (auth)) 1482 { 1483 if (DBUS_AUTH_IS_CLIENT (auth)) 1484 return (* auth->mech->client_encode_func) (auth, plaintext, encoded); 1485 else 1486 return (* auth->mech->server_encode_func) (auth, plaintext, encoded); 1487 } 1488 else 1489 { 1490 return _dbus_string_copy (plaintext, 0, encoded, 1491 _dbus_string_get_length (encoded)); 1492 } 1493} 1494 1495/** 1496 * Called post-authentication, indicates whether we need to decode 1497 * the message stream with _dbus_auth_decode_data() after 1498 * receiving it from the peer. 1499 * 1500 * @param auth the auth conversation 1501 * @returns #TRUE if we need to encode the stream 1502 */ 1503dbus_bool_t 1504_dbus_auth_needs_decoding (DBusAuth *auth) 1505{ 1506 if (!auth->authenticated) 1507 return FALSE; 1508 1509 if (auth->mech != NULL) 1510 { 1511 if (DBUS_AUTH_IS_CLIENT (auth)) 1512 return auth->mech->client_decode_func != NULL; 1513 else 1514 return auth->mech->server_decode_func != NULL; 1515 } 1516 else 1517 return FALSE; 1518} 1519 1520 1521/** 1522 * Called post-authentication, decodes a block of bytes received from 1523 * the peer. If no encoding was negotiated, just copies the bytes (you 1524 * can avoid this by checking _dbus_auth_needs_decoding()). 1525 * 1526 * @todo We need to be able to distinguish "out of memory" error 1527 * from "the data is hosed" error. 1528 * 1529 * @param auth the auth conversation 1530 * @param encoded the encoded data 1531 * @param plaintext initialized string where decoded data is appended 1532 * @returns #TRUE if we had enough memory and successfully decoded 1533 */ 1534dbus_bool_t 1535_dbus_auth_decode_data (DBusAuth *auth, 1536 const DBusString *encoded, 1537 DBusString *plaintext) 1538{ 1539 _dbus_assert (plaintext != encoded); 1540 1541 if (!auth->authenticated) 1542 return FALSE; 1543 1544 if (_dbus_auth_needs_decoding (auth)) 1545 { 1546 if (DBUS_AUTH_IS_CLIENT (auth)) 1547 return (* auth->mech->client_decode_func) (auth, encoded, plaintext); 1548 else 1549 return (* auth->mech->server_decode_func) (auth, encoded, plaintext); 1550 } 1551 else 1552 { 1553 return _dbus_string_copy (encoded, 0, plaintext, 1554 _dbus_string_get_length (plaintext)); 1555 } 1556} 1557 1558/** 1559 * Sets credentials received via reliable means from the operating 1560 * system. 1561 * 1562 * @param auth the auth conversation 1563 * @param credentials the credentials received 1564 */ 1565void 1566_dbus_auth_set_credentials (DBusAuth *auth, 1567 const DBusCredentials *credentials) 1568{ 1569 auth->credentials = *credentials; 1570} 1571 1572/** 1573 * Gets the identity we authorized the client as. Apps may have 1574 * different policies as to what identities they allow. 1575 * 1576 * @param auth the auth conversation 1577 * @param credentials the credentials we've authorized 1578 */ 1579void 1580_dbus_auth_get_identity (DBusAuth *auth, 1581 DBusCredentials *credentials) 1582{ 1583 if (auth->authenticated) 1584 { 1585 *credentials = auth->authorized_identity; 1586 } 1587 else 1588 { 1589 credentials->pid = -1; 1590 credentials->uid = -1; 1591 credentials->gid = -1; 1592 } 1593} 1594 1595/** @} */ 1596 1597#ifdef DBUS_BUILD_TESTS 1598#include "dbus-test.h" 1599#include <stdio.h> 1600 1601dbus_bool_t 1602_dbus_auth_test (const char *test_data_dir) 1603{ 1604 1605 1606 return TRUE; 1607} 1608 1609#endif /* DBUS_BUILD_TESTS */ 1610