PGSQL: Dissect SASL auth

Dissecting SASL and GSSAPI/SSPI authentication data
Ref: https://www.postgresql.org/docs/10/protocol-message-formats.html

Bug: 15286
Change-Id: I19fc18da105490bf053ce9ab39164fb345577266
Reviewed-on: https://code.wireshark.org/review/30723
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Uli Heilmeier 2018-11-19 21:17:19 +01:00 committed by Anders Broman
parent 5800ca9bb5
commit 4708ffdb99
1 changed files with 133 additions and 27 deletions

View File

@ -33,6 +33,10 @@ static int hf_query = -1;
static int hf_authtype = -1;
static int hf_passwd = -1;
static int hf_salt = -1;
static int hf_gssapi_sspi_data = -1;
static int hf_sasl_auth_mech = -1;
static int hf_sasl_auth_data = -1;
static int hf_sasl_auth_data_length = -1;
static int hf_statement = -1;
static int hf_portal = -1;
static int hf_return = -1;
@ -79,12 +83,20 @@ static gint ett_values = -1;
static gboolean pgsql_desegment = TRUE;
static gboolean first_message = TRUE;
typedef enum {
PGSQL_AUTH_STATE_NONE, /* No authentication seen or used */
PGSQL_AUTH_SASL_REQUESTED, /* Server sends SASL auth request with supported SASL mechanisms*/
PGSQL_AUTH_SASL_CONTINUE, /* Server and/or client send further SASL challange-response messages */
PGSQL_AUTH_GSSAPI_SSPI_DATA, /* GSSAPI/SSPI in use */
} pgsql_auth_state_t;
typedef struct pgsql_conn_data {
gboolean ssl_requested;
pgsql_auth_state_t auth_state; /* Current authentication state */
} pgsql_conn_data_t;
static const value_string fe_messages[] = {
{ 'p', "Password message" },
{ 'p', "Authentication message" },
{ 'Q', "Simple query" },
{ 'P', "Parse" },
{ 'B', "Bind" },
@ -127,21 +139,34 @@ static const value_string be_messages[] = {
{ 0, NULL }
};
#define PGSQL_AUTH_TYPE_SUCCESS 0
#define PGSQL_AUTH_TYPE_KERBEROS4 1
#define PGSQL_AUTH_TYPE_KERBEROS5 2
#define PGSQL_AUTH_TYPE_PLAINTEXT 3
#define PGSQL_AUTH_TYPE_CRYPT 4
#define PGSQL_AUTH_TYPE_MD5 5
#define PGSQL_AUTH_TYPE_SCM 6
#define PGSQL_AUTH_TYPE_GSSAPI 7
#define PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE 8
#define PGSQL_AUTH_TYPE_SSPI 9
#define PGSQL_AUTH_TYPE_SASL 10
#define PGSQL_AUTH_TYPE_SASL_CONTINUE 11
#define PGSQL_AUTH_TYPE_SASL_COMPLETE 12
static const value_string auth_types[] = {
{ 0, "Success" },
{ 1, "Kerberos V4" },
{ 2, "Kerberos V5" },
{ 3, "Plaintext password" },
{ 4, "crypt()ed password" },
{ 5, "MD5 password" },
{ 6, "SCM credentials" },
{ 7, "GSSAPI" },
{ 8, "GSSAPI/SSPI continue" },
{ 9, "SSPI" },
{10, "SASL" },
{11, "SASL continue" },
{12, "SASL complete" },
{ PGSQL_AUTH_TYPE_SUCCESS , "Success" },
{ PGSQL_AUTH_TYPE_KERBEROS4 , "Kerberos V4" },
{ PGSQL_AUTH_TYPE_KERBEROS5 , "Kerberos V5" },
{ PGSQL_AUTH_TYPE_PLAINTEXT , "Plaintext password" },
{ PGSQL_AUTH_TYPE_CRYPT , "crypt()ed password" },
{ PGSQL_AUTH_TYPE_MD5 , "MD5 password" },
{ PGSQL_AUTH_TYPE_SCM , "SCM credentials" },
{ PGSQL_AUTH_TYPE_GSSAPI , "GSSAPI" },
{ PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE , "GSSAPI/SSPI continue" },
{ PGSQL_AUTH_TYPE_SSPI , "SSPI" },
{ PGSQL_AUTH_TYPE_SASL , "SASL" },
{ PGSQL_AUTH_TYPE_SASL_CONTINUE , "SASL continue" },
{ PGSQL_AUTH_TYPE_SASL_COMPLETE , "SASL complete" },
{ 0, NULL }
};
@ -166,12 +191,39 @@ static void dissect_pgsql_fe_msg(guchar type, guint length, tvbuff_t *tvb,
gint i, siz;
char *s;
proto_tree *shrub;
gint32 data_length;
switch (type) {
/* Password */
/* Password, SASL or GSSAPI Response, depending on context */
case 'p':
siz = tvb_strsize(tvb, n);
proto_tree_add_item(tree, hf_passwd, tvb, n, siz, ENC_ASCII|ENC_NA);
switch(conv_data->auth_state) {
case PGSQL_AUTH_SASL_REQUESTED:
/* SASLInitResponse */
siz = tvb_strsize(tvb, n);
proto_tree_add_item(tree, hf_sasl_auth_mech, tvb, n, siz, ENC_ASCII|ENC_NA);
n += siz;
proto_tree_add_item_ret_int(tree, hf_sasl_auth_data_length, tvb, n, 4, ENC_BIG_ENDIAN, &data_length);
n += 4;
if (data_length) {
proto_tree_add_item(tree, hf_sasl_auth_data, tvb, n, data_length, ENC_NA);
n += data_length;
}
break;
case PGSQL_AUTH_SASL_CONTINUE:
proto_tree_add_item(tree, hf_sasl_auth_data, tvb, n, length-4, ENC_NA);
break;
case PGSQL_AUTH_GSSAPI_SSPI_DATA:
proto_tree_add_item(tree, hf_gssapi_sspi_data, tvb, n, length-4, ENC_NA);
break;
default:
siz = tvb_strsize(tvb, n);
proto_tree_add_item(tree, hf_passwd, tvb, n, siz, ENC_ASCII|ENC_NA);
break;
}
break;
/* Simple query */
@ -349,26 +401,48 @@ static void dissect_pgsql_fe_msg(guchar type, guint length, tvbuff_t *tvb,
static void dissect_pgsql_be_msg(guchar type, guint length, tvbuff_t *tvb,
gint n, proto_tree *tree)
gint n, proto_tree *tree,
pgsql_conn_data_t *conv_data)
{
guchar c;
gint i, siz;
char *s, *t;
proto_item *ti;
proto_tree *shrub;
guint32 auth_type;
switch (type) {
/* Authentication request */
case 'R':
proto_tree_add_item(tree, hf_authtype, tvb, n, 4, ENC_BIG_ENDIAN);
i = tvb_get_ntohl(tvb, n);
if (i == 4 || i == 5) {
/* i -= (6-i); :-) */
proto_tree_add_item_ret_uint(tree, hf_authtype, tvb, n, 4, ENC_BIG_ENDIAN, &auth_type);
switch (auth_type) {
case PGSQL_AUTH_TYPE_CRYPT:
case PGSQL_AUTH_TYPE_MD5:
n += 4;
siz = (i == 4 ? 2 : 4);
siz = (auth_type == PGSQL_AUTH_TYPE_CRYPT ? 2 : 4);
proto_tree_add_item(tree, hf_salt, tvb, n, siz, ENC_NA);
}else if (i == 8) {
proto_tree_add_item(tree, hf_salt, tvb, n, length-8, ENC_NA);
break;
case PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE:
conv_data->auth_state = PGSQL_AUTH_GSSAPI_SSPI_DATA;
proto_tree_add_item(tree, hf_gssapi_sspi_data, tvb, n, length-8, ENC_NA);
break;
case PGSQL_AUTH_TYPE_SASL:
conv_data->auth_state = PGSQL_AUTH_SASL_REQUESTED;
n += 4;
while ((guint)n < length) {
siz = tvb_strsize(tvb, n);
proto_tree_add_item(tree, hf_sasl_auth_mech, tvb, n, siz, ENC_ASCII|ENC_NA);
n += siz;
}
break;
case PGSQL_AUTH_TYPE_SASL_CONTINUE:
case PGSQL_AUTH_TYPE_SASL_COMPLETE:
conv_data->auth_state = PGSQL_AUTH_SASL_CONTINUE;
n += 4;
if ((guint)n < length) {
proto_tree_add_item(tree, hf_sasl_auth_data, tvb, n, length-8, ENC_NA);
}
break;
}
break;
@ -569,6 +643,7 @@ dissect_pgsql_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
if (!conn_data) {
conn_data = wmem_new(wmem_file_scope(), pgsql_conn_data_t);
conn_data->ssl_requested = FALSE;
conn_data->auth_state = PGSQL_AUTH_STATE_NONE;
conversation_add_proto_data(conversation, proto_pgsql, conn_data);
}
@ -596,6 +671,21 @@ dissect_pgsql_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
typestr = "Startup message";
else
typestr = "Unknown";
} else if (type == 'p') {
switch (conn_data->auth_state) {
case PGSQL_AUTH_SASL_REQUESTED:
typestr = "SASLInitialResponse message";
break;
case PGSQL_AUTH_SASL_CONTINUE:
typestr = "SASLResponse message";
break;
case PGSQL_AUTH_GSSAPI_SSPI_DATA:
typestr = "GSSResponse message";
break;
default:
typestr = "Password message";
break;
}
} else
typestr = val_to_str_const(type, fe_messages, "Unknown");
}
@ -626,7 +716,7 @@ dissect_pgsql_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* dat
if (fe)
dissect_pgsql_fe_msg(type, length, tvb, n, ptree, conn_data);
else
dissect_pgsql_be_msg(type, length, tvb, n, ptree);
dissect_pgsql_be_msg(type, length, tvb, n, ptree, conn_data);
}
return tvb_captured_length(tvb);
@ -710,7 +800,7 @@ proto_register_pgsql(void)
"A password.", HFILL }
},
{ &hf_authtype,
{ "Authentication type", "pgsql.authtype", FT_INT32, BASE_DEC,
{ "Authentication type", "pgsql.authtype", FT_UINT32, BASE_DEC,
VALS(auth_types), 0,
"The type of authentication requested by the backend.", HFILL }
},
@ -718,6 +808,22 @@ proto_register_pgsql(void)
{ "Salt value", "pgsql.salt", FT_BYTES, BASE_NONE, NULL, 0,
"The salt to use while encrypting a password.", HFILL }
},
{ &hf_gssapi_sspi_data,
{ "GSSAPI or SSPI data", "pgsql.auth.gssapi_sspi.data", FT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_sasl_auth_mech,
{ "SASL authentication mechanism", "pgsql.auth.sasl.mech", FT_STRINGZ, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_sasl_auth_data_length,
{ "SASL authentication data length", "pgsql.auth.sasl.data.length", FT_INT32, BASE_DEC, NULL, 0,
NULL, HFILL }
},
{ &hf_sasl_auth_data,
{ "SASL authentication data", "pgsql.auth.sasl.data", FT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL }
},
{ &hf_statement,
{ "Statement", "pgsql.statement", FT_STRINGZ, BASE_NONE, NULL, 0,
"The name of a prepared statement.", HFILL }