2002-12-25 Havoc Pennington <hp@pobox.com>

* doc/dbus-sasl-profile.txt: docs on the authentication protocol,
	it is a simple protocol that just maps directly to SASL.

	* dbus/dbus-auth.h, dbus/dbus-auth.c: authentication protocol
	initial implementation, not actually used yet.

	* dbus/dbus-string.c (_dbus_string_find): new function
	(_dbus_string_equal): new function
	(_dbus_string_base64_encode): new function
	(_dbus_string_base64_decode): new function
This commit is contained in:
Havoc Pennington 2002-12-25 18:00:10 +00:00
parent f25559f534
commit 2297787455
8 changed files with 2282 additions and 9 deletions

View file

@ -1,3 +1,16 @@
2002-12-25 Havoc Pennington <hp@pobox.com>
* doc/dbus-sasl-profile.txt: docs on the authentication protocol,
it is a simple protocol that just maps directly to SASL.
* dbus/dbus-auth.h, dbus/dbus-auth.c: authentication protocol
initial implementation, not actually used yet.
* dbus/dbus-string.c (_dbus_string_find): new function
(_dbus_string_equal): new function
(_dbus_string_base64_encode): new function
(_dbus_string_base64_decode): new function
2002-12-25 Anders Carlsson <andersca@codefactory.se>
* dbus/Makefile.am:

View file

@ -17,6 +17,8 @@ dbusinclude_HEADERS= \
dbus-types.h
libdbus_1_la_SOURCES= \
dbus-auth.c \
dbus-auth.h \
dbus-connection.c \
dbus-connection-internal.h \
dbus-errors.c \

1215
dbus/dbus-auth.c Normal file

File diff suppressed because it is too large Load diff

66
dbus/dbus-auth.h Normal file
View file

@ -0,0 +1,66 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-auth.h Authentication
*
* Copyright (C) 2002 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef DBUS_AUTH_H
#define DBUS_AUTH_H
#include <dbus/dbus-macros.h>
#include <dbus/dbus-errors.h>
#include <dbus/dbus-string.h>
DBUS_BEGIN_DECLS;
typedef struct DBusAuth DBusAuth;
typedef enum
{
DBUS_AUTH_STATE_WAITING_FOR_INPUT,
DBUS_AUTH_STATE_WAITING_FOR_MEMORY,
DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND,
DBUS_AUTH_STATE_NEED_DISCONNECT,
DBUS_AUTH_STATE_AUTHENTICATED
} DBusAuthState;
DBusAuth* _dbus_auth_server_new (void);
DBusAuth* _dbus_auth_client_new (void);
void _dbus_auth_ref (DBusAuth *auth);
void _dbus_auth_unref (DBusAuth *auth);
DBusAuthState _dbus_auth_do_work (DBusAuth *auth);
dbus_bool_t _dbus_auth_get_bytes_to_send (DBusAuth *auth,
DBusString *str);
dbus_bool_t _dbus_auth_bytes_received (DBusAuth *auth,
const DBusString *str);
dbus_bool_t _dbus_auth_get_unused_bytes (DBusAuth *auth,
DBusString *str);
dbus_bool_t _dbus_auth_needs_encoding (DBusAuth *auth);
dbus_bool_t _dbus_auth_encode_data (DBusAuth *auth,
const DBusString *plaintext,
DBusString *encoded);
dbus_bool_t _dbus_auth_needs_decoding (DBusAuth *auth);
dbus_bool_t _dbus_auth_decode_data (DBusAuth *auth,
const DBusString *encoded,
DBusString *plaintext);
DBUS_END_DECLS;
#endif /* DBUS_AUTH_H */

View file

@ -711,11 +711,9 @@ _dbus_string_delete (DBusString *str,
}
static dbus_bool_t
copy (DBusRealString *source,
int start,
int len,
DBusRealString *dest,
int insert_at)
open_gap (int len,
DBusRealString *dest,
int insert_at)
{
if (len == 0)
return TRUE;
@ -727,6 +725,19 @@ copy (DBusRealString *source,
dest->str + insert_at,
dest->len - len);
return TRUE;
}
static dbus_bool_t
copy (DBusRealString *source,
int start,
int len,
DBusRealString *dest,
int insert_at)
{
if (!open_gap (len, dest, insert_at))
return FALSE;
memcpy (dest->str + insert_at,
source->str + start,
len);
@ -1003,6 +1014,579 @@ _dbus_string_get_unichar (const DBusString *str,
*end_return = start + len;
}
/**
* Finds the given substring in the string,
* returning #TRUE and filling in the byte index
* where the substring was found, if it was found.
* Returns #FALSE if the substring wasn't found.
* Sets *start to the length of the string if the substring
* is not found.
*
* @param str the string
* @param start where to start looking
* @param substr the substring
* @param found return location for where it was found, or #NULL
* @returns #TRUE if found
*/
dbus_bool_t
_dbus_string_find (const DBusString *str,
int start,
const char *substr,
int *found)
{
int i;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (substr != NULL);
_dbus_assert (start <= real->len);
/* we always "find" an empty string */
if (*substr == '\0')
{
if (found)
*found = 0;
return TRUE;
}
i = start;
while (i < real->len)
{
if (real->str[i] == substr[0])
{
int j = i + 1;
while (j < real->len)
{
if (substr[j - i] == '\0')
break;
else if (real->str[j] != substr[j - i])
break;
++j;
}
if (substr[j - i] == '\0')
{
if (found)
*found = i;
return TRUE;
}
}
++i;
}
if (found)
*found = real->len;
return FALSE;
}
/**
* Finds a blank (space or tab) in the string. Returns #TRUE
* if found, #FALSE otherwise. If a blank is not found sets
* *found to the length of the string.
*
* @param str the string
* @param start byte index to start looking
* @param found place to store the location of the first blank
* @returns #TRUE if a blank was found
*/
dbus_bool_t
_dbus_string_find_blank (const DBusString *str,
int start,
int *found)
{
int i;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (start <= real->len);
i = start;
while (i < real->len)
{
if (real->str[i] == ' ' ||
real->str[i] == '\t')
{
if (found)
*found = i;
return TRUE;
}
++i;
}
if (found)
*found = real->len;
return FALSE;
}
/**
* Skips blanks from start, storing the first non-blank in *end
*
* @param str the string
* @param start where to start
* @param end where to store the first non-blank byte index
*/
void
_dbus_string_skip_blank (const DBusString *str,
int start,
int *end)
{
int i;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (start <= real->len);
i = start;
while (i < real->len)
{
if (real->str[i] != ' ' ||
real->str[i] != '\t')
break;
++i;
}
if (end)
*end = i;
}
/**
* Tests two DBusString for equality.
*
* @param a first string
* @param b second string
* @returns #TRUE if equal
*/
dbus_bool_t
_dbus_string_equal (const DBusString *a,
const DBusString *b)
{
const unsigned char *ap;
const unsigned char *bp;
const unsigned char *a_end;
const DBusRealString *real_a = (const DBusRealString*) a;
const DBusRealString *real_b = (const DBusRealString*) b;
DBUS_GENERIC_STRING_PREAMBLE (real_a);
DBUS_GENERIC_STRING_PREAMBLE (real_b);
if (real_a->len != real_b->len)
return FALSE;
ap = real_a->str;
bp = real_b->str;
a_end = real_a->str + real_a->len;
while (ap != a_end)
{
if (*ap != *bp)
return FALSE;
++ap;
++bp;
}
return TRUE;
}
/**
* Checks whether a string is equal to a C string.
*
* @param a the string
* @param c_str the C string
* @returns #TRUE if equal
*/
dbus_bool_t
_dbus_string_equal_c_str (const DBusString *a,
const char *c_str)
{
const unsigned char *ap;
const unsigned char *bp;
const unsigned char *a_end;
const DBusRealString *real_a = (const DBusRealString*) a;
DBUS_GENERIC_STRING_PREAMBLE (real_a);
ap = real_a->str;
bp = (const unsigned char*) c_str;
a_end = real_a->str + real_a->len;
while (ap != a_end && *bp)
{
if (*ap != *bp)
return FALSE;
++ap;
++bp;
}
if (*ap && *bp == '\0')
return FALSE;
else if (ap == a_end && *bp)
return FALSE;
return TRUE;
}
static const signed char base64_table[] = {
/* 0 */ 'A',
/* 1 */ 'B',
/* 2 */ 'C',
/* 3 */ 'D',
/* 4 */ 'E',
/* 5 */ 'F',
/* 6 */ 'G',
/* 7 */ 'H',
/* 8 */ 'I',
/* 9 */ 'J',
/* 10 */ 'K',
/* 11 */ 'L',
/* 12 */ 'M',
/* 13 */ 'N',
/* 14 */ 'O',
/* 15 */ 'P',
/* 16 */ 'Q',
/* 17 */ 'R',
/* 18 */ 'S',
/* 19 */ 'T',
/* 20 */ 'U',
/* 21 */ 'V',
/* 22 */ 'W',
/* 23 */ 'X',
/* 24 */ 'Y',
/* 25 */ 'Z',
/* 26 */ 'a',
/* 27 */ 'b',
/* 28 */ 'c',
/* 29 */ 'd',
/* 30 */ 'e',
/* 31 */ 'f',
/* 32 */ 'g',
/* 33 */ 'h',
/* 34 */ 'i',
/* 35 */ 'j',
/* 36 */ 'k',
/* 37 */ 'l',
/* 38 */ 'm',
/* 39 */ 'n',
/* 40 */ 'o',
/* 41 */ 'p',
/* 42 */ 'q',
/* 43 */ 'r',
/* 44 */ 's',
/* 45 */ 't',
/* 46 */ 'u',
/* 47 */ 'v',
/* 48 */ 'w',
/* 49 */ 'x',
/* 50 */ 'y',
/* 51 */ 'z',
/* 52 */ '0',
/* 53 */ '1',
/* 54 */ '2',
/* 55 */ '3',
/* 56 */ '4',
/* 57 */ '5',
/* 58 */ '6',
/* 59 */ '7',
/* 60 */ '8',
/* 61 */ '9',
/* 62 */ '+',
/* 63 */ '/'
};
/** The minimum char that's a valid char in Base64-encoded text */
#define UNBASE64_MIN_CHAR (43)
/** The maximum char that's a valid char in Base64-encoded text */
#define UNBASE64_MAX_CHAR (122)
/** Must subtract this from a char's integer value before offsetting
* into unbase64_table
*/
#define UNBASE64_TABLE_OFFSET UNBASE64_MIN_CHAR
static const signed char unbase64_table[] = {
/* 43 + */ 62,
/* 44 , */ -1,
/* 45 - */ -1,
/* 46 . */ -1,
/* 47 / */ 63,
/* 48 0 */ 52,
/* 49 1 */ 53,
/* 50 2 */ 54,
/* 51 3 */ 55,
/* 52 4 */ 56,
/* 53 5 */ 57,
/* 54 6 */ 58,
/* 55 7 */ 59,
/* 56 8 */ 60,
/* 57 9 */ 61,
/* 58 : */ -1,
/* 59 ; */ -1,
/* 60 < */ -1,
/* 61 = */ -1,
/* 62 > */ -1,
/* 63 ? */ -1,
/* 64 @ */ -1,
/* 65 A */ 0,
/* 66 B */ 1,
/* 67 C */ 2,
/* 68 D */ 3,
/* 69 E */ 4,
/* 70 F */ 5,
/* 71 G */ 6,
/* 72 H */ 7,
/* 73 I */ 8,
/* 74 J */ 9,
/* 75 K */ 10,
/* 76 L */ 11,
/* 77 M */ 12,
/* 78 N */ 13,
/* 79 O */ 14,
/* 80 P */ 15,
/* 81 Q */ 16,
/* 82 R */ 17,
/* 83 S */ 18,
/* 84 T */ 19,
/* 85 U */ 20,
/* 86 V */ 21,
/* 87 W */ 22,
/* 88 X */ 23,
/* 89 Y */ 24,
/* 90 Z */ 25,
/* 91 [ */ -1,
/* 92 \ */ -1,
/* 93 ] */ -1,
/* 94 ^ */ -1,
/* 95 _ */ -1,
/* 96 ` */ -1,
/* 97 a */ 26,
/* 98 b */ 27,
/* 99 c */ 28,
/* 100 d */ 29,
/* 101 e */ 30,
/* 102 f */ 31,
/* 103 g */ 32,
/* 104 h */ 33,
/* 105 i */ 34,
/* 106 j */ 35,
/* 107 k */ 36,
/* 108 l */ 37,
/* 109 m */ 38,
/* 110 n */ 39,
/* 111 o */ 40,
/* 112 p */ 41,
/* 113 q */ 42,
/* 114 r */ 43,
/* 115 s */ 44,
/* 116 t */ 45,
/* 117 u */ 46,
/* 118 v */ 47,
/* 119 w */ 48,
/* 120 x */ 49,
/* 121 y */ 50,
/* 122 z */ 51
};
/**
* Encodes a string using Base64, as documented in RFC 2045.
*
* @param source the string to encode
* @param start byte index to start encoding
* @param dest string where encoded data should be placed
* @param insert_at where to place encoded data
* @returns #TRUE if encoding was successful, #FALSE if no memory etc.
*/
dbus_bool_t
_dbus_string_base64_encode (const DBusString *source,
int start,
DBusString *dest,
int insert_at)
{
int source_len;
int dest_len;
const unsigned char *s;
unsigned char *d;
const unsigned char *triplet_end;
const unsigned char *final_end;
DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
/* For each 24 bits (3 bytes) of input, we have 4 chars of
* output.
*/
source_len = real_source->len - start;
dest_len = (source_len / 3) * 4;
if (source_len % 3 != 0)
dest_len += 4;
if (source_len == 0)
return TRUE;
if (!open_gap (dest_len, real_dest, insert_at))
return FALSE;
d = real_dest->str + insert_at;
s = real_source->str + start;
final_end = real_source->str + (start + source_len);
triplet_end = final_end - (source_len % 3);
_dbus_assert (triplet_end <= final_end);
_dbus_assert ((final_end - triplet_end) < 3);
#define ENCODE_64(v) (base64_table[ (unsigned char) (v) ])
#define SIX_BITS_MASK (0x3f)
_dbus_assert (SIX_BITS_MASK < _DBUS_N_ELEMENTS (base64_table));
while (s != triplet_end)
{
unsigned int triplet;
triplet = s[0] | (s[1] << 8) | (s[2] << 16);
/* Encode each 6 bits */
*d++ = ENCODE_64 (triplet >> 18);
*d++ = ENCODE_64 ((triplet >> 12) & SIX_BITS_MASK);
*d++ = ENCODE_64 ((triplet >> 6) & SIX_BITS_MASK);
*d++ = ENCODE_64 (triplet & SIX_BITS_MASK);
s += 3;
}
switch (final_end - triplet_end)
{
case 2:
{
unsigned int doublet;
doublet = s[0] | (s[1] << 8);
*d++ = ENCODE_64 (doublet >> 12);
*d++ = ENCODE_64 ((doublet >> 6) & SIX_BITS_MASK);
*d++ = ENCODE_64 (doublet & SIX_BITS_MASK);
*d++ = '=';
}
break;
case 1:
{
unsigned int singlet;
singlet = s[0];
*d++ = ENCODE_64 ((singlet >> 6) & SIX_BITS_MASK);
*d++ = ENCODE_64 (singlet & SIX_BITS_MASK);
*d++ = '=';
*d++ = '=';
}
break;
case 0:
break;
}
_dbus_assert (d == (real_dest->str + (insert_at + dest_len)));
return TRUE;
}
/**
* Decodes a string from Base64, as documented in RFC 2045.
*
* @param source the string to decode
* @param start byte index to start decode
* @param dest string where decoded data should be placed
* @param insert_at where to place decoded data
* @returns #TRUE if decoding was successful, #FALSE if no memory etc.
*/
dbus_bool_t
_dbus_string_base64_decode (const DBusString *source,
int start,
DBusString *dest,
int insert_at)
{
int source_len;
const char *s;
const char *end;
DBusString result;
unsigned int triplet = 0;
int sextet_count;
int pad_count;
DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
source_len = real_source->len - start;
s = real_source->str + start;
end = real_source->str + source_len;
if (source_len == 0)
return TRUE;
if (!_dbus_string_init (&result, _DBUS_INT_MAX))
return FALSE;
pad_count = 0;
sextet_count = 0;
while (s != end)
{
/* The idea is to just skip anything that isn't
* a base64 char - it's allowed to have whitespace,
* newlines, etc. in here. We also ignore trailing
* base64 chars, though that's suspicious.
*/
if (*s >= UNBASE64_MIN_CHAR &&
*s <= UNBASE64_MAX_CHAR)
{
if (*s == '=')
{
/* '=' is padding, doesn't represent additional data
* but does increment our count.
*/
pad_count += 1;
sextet_count += 1;
}
else
{
int val;
val = unbase64_table[(*s) - UNBASE64_TABLE_OFFSET];
if (val >= 0)
{
triplet <<= 6;
triplet |= (unsigned int) val;
sextet_count += 1;
}
}
if (sextet_count == 4)
{
/* no pad = 3 bytes, 1 pad = 2 bytes, 2 pad = 1 byte */
_dbus_string_append_byte (&result,
triplet & 0xff);
if (pad_count < 2)
_dbus_string_append_byte (&result,
(triplet >> 8) & 0xff);
if (pad_count < 1)
_dbus_string_append_byte (&result,
triplet >> 16);
sextet_count = 0;
pad_count = 0;
triplet = 0;
}
}
++s;
}
if (!_dbus_string_move (&result, 0, dest, insert_at))
{
_dbus_string_free (&result);
return FALSE;
}
_dbus_string_free (&result);
return TRUE;
}
/** @} */
#ifdef DBUS_BUILD_TESTS
@ -1029,6 +1613,54 @@ test_max_len (DBusString *str,
_dbus_assert_not_reached ("setting len to zero should have worked");
}
static void
test_base64_roundtrip (const unsigned char *data,
int len)
{
DBusString orig;
DBusString encoded;
DBusString decoded;
if (len < 0)
len = strlen (data);
if (!_dbus_string_init (&orig, _DBUS_INT_MAX))
_dbus_assert_not_reached ("could not init string");
if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
_dbus_assert_not_reached ("could not init string");
if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
_dbus_assert_not_reached ("could not init string");
if (!_dbus_string_append_len (&orig, data, len))
_dbus_assert_not_reached ("couldn't append orig data");
if (!_dbus_string_base64_encode (&orig, 0, &encoded, 0))
_dbus_assert_not_reached ("could not encode");
if (!_dbus_string_base64_decode (&encoded, 0, &decoded, 0))
_dbus_assert_not_reached ("could not decode");
if (!_dbus_string_equal (&orig, &decoded))
{
const char *s;
printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n",
_dbus_string_get_length (&orig),
_dbus_string_get_length (&encoded),
_dbus_string_get_length (&decoded));
printf ("Original: %s\n", data);
_dbus_string_get_const_data (&decoded, &s);
printf ("Decoded: %s\n", s);
_dbus_assert_not_reached ("original string not the same as string decoded from base64");
}
_dbus_string_free (&orig);
_dbus_string_free (&encoded);
_dbus_string_free (&decoded);
}
/**
* @ingroup DBusStringInternals
* Unit test for DBusString.
@ -1219,6 +1851,93 @@ _dbus_string_test (void)
_dbus_string_free (&str);
/* Test find */
if (!_dbus_string_init (&str, _DBUS_INT_MAX))
_dbus_assert_not_reached ("failed to init string");
if (!_dbus_string_append (&str, "Hello"))
_dbus_assert_not_reached ("couldn't append to string");
if (!_dbus_string_find (&str, 0, "He", &i))
_dbus_assert_not_reached ("didn't find 'He'");
_dbus_assert (i == 0);
if (!_dbus_string_find (&str, 0, "ello", &i))
_dbus_assert_not_reached ("didn't find 'ello'");
_dbus_assert (i == 1);
if (!_dbus_string_find (&str, 0, "lo", &i))
_dbus_assert_not_reached ("didn't find 'lo'");
_dbus_assert (i == 3);
if (!_dbus_string_find (&str, 2, "lo", &i))
_dbus_assert_not_reached ("didn't find 'lo'");
_dbus_assert (i == 3);
if (_dbus_string_find (&str, 4, "lo", &i))
_dbus_assert_not_reached ("did find 'lo'");
if (!_dbus_string_find (&str, 0, "l", &i))
_dbus_assert_not_reached ("didn't find 'l'");
_dbus_assert (i == 2);
if (!_dbus_string_find (&str, 0, "H", &i))
_dbus_assert_not_reached ("didn't find 'H'");
_dbus_assert (i == 0);
if (!_dbus_string_find (&str, 0, "", &i))
_dbus_assert_not_reached ("didn't find ''");
_dbus_assert (i == 0);
if (_dbus_string_find (&str, 0, "Hello!", NULL))
_dbus_assert_not_reached ("Did find 'Hello!'");
if (_dbus_string_find (&str, 0, "Oh, Hello", NULL))
_dbus_assert_not_reached ("Did find 'Oh, Hello'");
if (_dbus_string_find (&str, 0, "ill", NULL))
_dbus_assert_not_reached ("Did find 'ill'");
if (_dbus_string_find (&str, 0, "q", NULL))
_dbus_assert_not_reached ("Did find 'q'");
_dbus_string_free (&str);
/* Base 64 */
test_base64_roundtrip ("Hello this is a string\n", -1);
test_base64_roundtrip ("Hello this is a string\n1", -1);
test_base64_roundtrip ("Hello this is a string\n12", -1);
test_base64_roundtrip ("Hello this is a string\n123", -1);
test_base64_roundtrip ("Hello this is a string\n1234", -1);
test_base64_roundtrip ("Hello this is a string\n12345", -1);
test_base64_roundtrip ("", 0);
test_base64_roundtrip ("1", 1);
test_base64_roundtrip ("12", 2);
test_base64_roundtrip ("123", 3);
test_base64_roundtrip ("1234", 4);
test_base64_roundtrip ("12345", 5);
test_base64_roundtrip ("", 1);
test_base64_roundtrip ("1", 2);
test_base64_roundtrip ("12", 3);
test_base64_roundtrip ("123", 4);
test_base64_roundtrip ("1234", 5);
test_base64_roundtrip ("12345", 6);
{
unsigned char buf[512];
i = 0;
while (i < _DBUS_N_ELEMENTS (buf))
{
buf[i] = i;
++i;
}
i = 0;
while (i < _DBUS_N_ELEMENTS (buf))
{
test_base64_roundtrip (buf, i);
++i;
}
}
return TRUE;
}

View file

@ -131,6 +131,33 @@ dbus_bool_t _dbus_string_parse_double (const DBusString *str,
double *value,
int *end_return);
dbus_bool_t _dbus_string_find (const DBusString *str,
int start,
const char *substr,
int *found);
dbus_bool_t _dbus_string_find_blank (const DBusString *str,
int start,
int *found);
void _dbus_string_skip_blank (const DBusString *str,
int start,
int *end);
dbus_bool_t _dbus_string_equal (const DBusString *a,
const DBusString *b);
dbus_bool_t _dbus_string_equal_c_str (const DBusString *a,
const char *c_str);
dbus_bool_t _dbus_string_base64_encode (const DBusString *source,
int start,
DBusString *dest,
int insert_at);
dbus_bool_t _dbus_string_base64_decode (const DBusString *source,
int start,
DBusString *dest,
int insert_at);
DBUS_END_DECLS;

View file

@ -37,6 +37,10 @@ int
main (int argc,
char **argv)
{
printf ("%s: running string tests\n", argv[0]);
if (!_dbus_string_test ())
die ("strings");
printf ("%s: running marshalling tests\n", argv[0]);
if (!_dbus_marshal_test ())
die ("marshalling");
@ -45,10 +49,6 @@ main (int argc,
if (!_dbus_mem_pool_test ())
die ("memory pools");
printf ("%s: running string tests\n", argv[0]);
if (!_dbus_string_test ())
die ("strings");
printf ("%s: running linked list tests\n", argv[0]);
if (!_dbus_list_test ())
die ("lists");

231
doc/dbus-sasl-profile.txt Normal file
View file

@ -0,0 +1,231 @@
D-BUS Authentication
===
This document defines a small plain-text protocol used to perform
authentication and negotiate a security layer before the flow of D-BUS
messages begins. This protocol is intended to be a profile of the
Simple Authentication and Session Layer [SASL].
This document is loosely based on the POP3 SASL profile by John Myers.
Conventions Used in this Document
===
In examples, "C:" and "S:" indicate lines sent by the client and
server respectively.
The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
in this document are to be interpreted as defined in "Key words for
use in RFCs to Indicate Requirement Levels" [RFC 2119]
Overview
===
The protocol is a line-based protocol, where each line ends with
\r\n. Each line begins with an all-caps ASCII command name containing
only the character range [A-Z], a space, then any arguments for the
command, then the \r\n ending the line. The protocol is
case-sensitive.
Commands from the client to the server are as follows:
AUTH [mechanism] [initial-response]
CANCEL
BEGIN
DATA <data in base 64 encoding>
ERROR [human-readable error explanation]
From server to client are as follows:
MECHANISMS <space-separated list of mechanism names>
REJECTED
OK
DATA <data in base 64 encoding>
ERROR
AUTH Command
===
If an AUTH command has no arguments, it is a request to list
available mechanisms. The server SHOULD respond with a MECHANISMS
command listing the mechanisms it understands.
If an AUTH command specifies a mechanism, and the server supports
said mechanism, the server SHOULD begin exchanging SASL
challenge-response data with the client using DATA commands.
If the server does not support the mechanism given in the AUTH
command, it SHOULD send a MECHANISMS command listing the mechanisms
it does support. A MECHANISMS command implies that any
authentication in progress was rejected, as if REJECTED were also
sent. A server MAY send a REJECTED command instead of a MECHANISMS
command, though this is unhelpful.
If the [initial-response] argument is provided, it is intended for
use with mechanisms that have no initial challenge (or an empty
initial challenge), as if it were the argument to an initial DATA
command. If the selected mechanism has an initial challenge, the
server should reject authentication (send MECHANISMS or REJECTED).
If authentication succeeds after exchanging DATA commands,
an OK command should be sent to the client.
The first octet received by the client after the \r\n of the OK
command MUST be the first octet of the authenticated/encrypted
stream of D-BUS messages.
The first octet received by the server after the \r\n of the BEGIN
command from the client MUST be the first octet of the
authenticated/encrypted stream of D-BUS messages.
CANCEL Command
===
At any time up to sending the BEGIN command, the client may
send a CANCEL command. On receiving the CANCEL command, the
server MUST send a REJECTED or MECHANISMS command and abort the
current authentication exchange.
DATA Command
===
The DATA command may come from either client or server, and simply
contains a base64-encoded block of data to be interpreted
according to the SASL mechanism in use.
BEGIN Command
===
The BEGIN command acknowledges that the client has received an
OK command from the server, and that the stream of messages
is about to begin.
The first octet received by the server after the \r\n of the BEGIN
command from the client MUST be the first octet of the
authenticated/encrypted stream of D-BUS messages.
MECHANISMS Command
===
The MECHANISMS command has a space-separated list of
available auth mechanisms as arguments. The MECHANISMS command
implies REJECTED if an authentication exchange is in progress;
the current exchange MUST be considered rejected.
REJECTED Command
===
The REJECTED command indicates that the current authentication
exchange has failed, and further exchange of DATA is inappropriate.
The client would normally try another mechanism, or try providing
different responses to challenges.
OK Command
===
The OK command indicates that the client has been authenticated,
and that further communication will be a stream of D-BUS messages
(optionally encrypted, as negotiated) rather than this protocol.
The first octet received by the client after the \r\n of the OK
command MUST be the first octet of the authenticated/encrypted
stream of D-BUS messages.
The client MUST respond to the OK command by sending a BEGIN
command, followed by its stream of messages, or by disconnecting.
The server MUST NOT accept additional commands using this protocol
after the OK command has been sent.
ERROR Command
===
The ERROR command indicates that either server or client did not
know a command, does not accept the given command in the current
context, or did not understand the arguments to the command. This
allows the protocol to be extended; a client or server can send a
command present or permitted only in new protocol versions, and if
an ERROR is received instead of an appropriate response, fall back
to using some other technique.
If an ERROR is sent, the server or client MUST continue as if the
command causing the ERROR had never been received.
Example of successful magic cookie authentication
===
(MAGIC_COOKIE is a made up mechanism)
C: AUTH MAGIC_COOKIE BsAY3g4gBNo=
S: OK
C: BEGIN
Example of finding out mechanisms then picking one
===
C: AUTH
S: MECHANISMS KERBEROS_V4 SKEY
C: AUTH SKEY bW9yZ2Fu
S: DATA OTUgUWE1ODMwOA==
C: DATA Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
S: OK
C: BEGIN
Example of client sends unknown command then falls back to regular auth
===
C: FOOBAR
S: ERROR
C: AUTH MAGIC_COOKIE BsAY3g4gBNo=
S: OK
C: BEGIN
Example of server doesn't support initial auth mechanism
===
C: AUTH MAGIC_COOKIE BsAY3g4gBNo=
S: MECHANISMS KERBEROS_V4 SKEY
C: AUTH SKEY bW9yZ2Fu
S: DATA OTUgUWE1ODMwOA==
C: DATA Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
S: OK
C: BEGIN
Example of wrong password or the like followed by successful retry
===
C: AUTH MAGIC_COOKIE BsAY3g4gBNo=
S: MECHANISMS KERBEROS_V4 SKEY
C: AUTH SKEY bW9yZ2Fu
S: DATA OTUgUWE1ODMwOA==
C: DATA Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
S: REJECTED
C: AUTH SKEY bW9yZ2Fu
S: DATA OTUgUWE1ODMwOA==
C: DATA Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
S: OK
C: BEGIN
Example of skey canceled and restarted
===
C: AUTH MAGIC_COOKIE BsAY3g4gBNo=
S: MECHANISMS KERBEROS_V4 SKEY
C: AUTH SKEY bW9yZ2Fu
S: DATA OTUgUWE1ODMwOA==
C: CANCEL
S: REJECTED
C: AUTH SKEY bW9yZ2Fu
S: DATA OTUgUWE1ODMwOA==
C: DATA Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
S: OK
C: BEGIN