Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-pgsql.c
blobb3d995355ddce7c1931c304a4c56111239afe2fd
1 /* packet-pgsql.c
2 * Routines for PostgreSQL v3 protocol dissection.
3 * <http://www.postgresql.org/docs/current/static/protocol.html>
4 * Copyright 2004 Abhijit Menon-Sen <ams@oryx.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "config.h"
15 #include <epan/packet.h>
17 #include "packet-gssapi.h"
18 #include "packet-tls-utils.h"
19 #include "packet-tcp.h"
21 void proto_register_pgsql(void);
22 void proto_reg_handoff_pgsql(void);
24 static dissector_handle_t pgsql_handle;
25 static dissector_handle_t pgsql_gssapi_handle;
26 static dissector_handle_t tls_handle;
27 static dissector_handle_t gssapi_handle;
28 static dissector_handle_t ntlmssp_handle;
30 static int proto_pgsql;
31 static int hf_frontend;
32 static int hf_type;
33 static int hf_length;
34 static int hf_version_major;
35 static int hf_version_minor;
36 static int hf_request_code;
37 static int hf_supported_minor_version;
38 static int hf_number_nonsupported_options;
39 static int hf_nonsupported_option;
40 static int hf_parameter_name;
41 static int hf_parameter_value;
42 static int hf_query;
43 static int hf_authtype;
44 static int hf_passwd;
45 static int hf_salt;
46 static int hf_gssapi_sspi_data;
47 static int hf_sasl_auth_mech;
48 static int hf_sasl_auth_data;
49 static int hf_sasl_auth_data_length;
50 static int hf_statement;
51 static int hf_portal;
52 static int hf_return;
53 static int hf_tag;
54 static int hf_status;
55 static int hf_copydata;
56 static int hf_error;
57 static int hf_pid;
58 static int hf_key;
59 static int hf_condition;
60 static int hf_text;
61 static int hf_tableoid;
62 static int hf_typeoid;
63 static int hf_oid;
64 static int hf_format;
65 static int hf_field_count;
66 static int hf_val_name;
67 static int hf_val_idx;
68 static int hf_val_length;
69 static int hf_val_data;
70 static int hf_val_mod;
71 static int hf_severity;
72 static int hf_code;
73 static int hf_message;
74 static int hf_detail;
75 static int hf_hint;
76 static int hf_position;
77 static int hf_internal_position;
78 static int hf_internal_query;
79 static int hf_where;
80 static int hf_schema_name;
81 static int hf_table_name;
82 static int hf_column_name;
83 static int hf_type_name;
84 static int hf_constraint_name;
85 static int hf_file;
86 static int hf_line;
87 static int hf_routine;
88 static int hf_ssl_response;
89 static int hf_gssenc_response;
90 static int hf_gssapi_encrypted_payload;
92 static int ett_pgsql;
93 static int ett_values;
95 #define PGSQL_PORT 5432
96 static bool pgsql_desegment = true;
97 static bool first_message = true;
99 typedef enum {
100 /* Reserve 0 (== GPOINTER_TO_UINT(NULL)) for no PGSQL detected */
101 PGSQL_AUTH_STATE_NONE = 1, /* No authentication seen or used */
102 PGSQL_AUTH_SASL_REQUESTED, /* Server sends SASL auth request with supported SASL mechanisms*/
103 PGSQL_AUTH_SASL_CONTINUE, /* Server and/or client send further SASL challenge-response messages */
104 PGSQL_AUTH_GSSAPI_SSPI_DATA, /* GSSAPI/SSPI in use */
105 PGSQL_AUTH_SSL_REQUESTED, /* Client sends SSL encryption request */
106 PGSQL_AUTH_GSSENC_REQUESTED, /* Client sends GSSAPI encryption request */
107 } pgsql_auth_state_t;
109 typedef struct pgsql_conn_data {
110 wmem_tree_t *state_tree; /* Tree of encryption and auth state changes */
111 uint32_t server_port;
112 } pgsql_conn_data_t;
114 static const value_string fe_messages[] = {
115 { 'p', "Authentication message" },
116 { 'Q', "Simple query" },
117 { 'P', "Parse" },
118 { 'B', "Bind" },
119 { 'E', "Execute" },
120 { 'D', "Describe" },
121 { 'C', "Close" },
122 { 'H', "Flush" },
123 { 'S', "Sync" },
124 { 'F', "Function call" },
125 { 'd', "Copy data" },
126 { 'c', "Copy completion" },
127 { 'f', "Copy failure" },
128 { 'X', "Termination" },
129 { 0, NULL }
132 static const value_string be_messages[] = {
133 { 'R', "Authentication request" },
134 { 'K', "Backend key data" },
135 { 'S', "Parameter status" },
136 { '1', "Parse completion" },
137 { '2', "Bind completion" },
138 { '3', "Close completion" },
139 { 'C', "Command completion" },
140 { 't', "Parameter description" },
141 { 'T', "Row description" },
142 { 'D', "Data row" },
143 { 'I', "Empty query" },
144 { 'n', "No data" },
145 { 'E', "Error" },
146 { 'N', "Notice" },
147 { 's', "Portal suspended" },
148 { 'Z', "Ready for query" },
149 { 'A', "Notification" },
150 { 'V', "Function call response" },
151 { 'G', "CopyIn response" },
152 { 'H', "CopyOut response" },
153 { 'd', "Copy data" },
154 { 'c', "Copy completion" },
155 { 'v', "Negotiate protocol version" },
156 { 0, NULL }
159 #define PGSQL_AUTH_TYPE_SUCCESS 0
160 #define PGSQL_AUTH_TYPE_KERBEROS4 1
161 #define PGSQL_AUTH_TYPE_KERBEROS5 2
162 #define PGSQL_AUTH_TYPE_PLAINTEXT 3
163 #define PGSQL_AUTH_TYPE_CRYPT 4
164 #define PGSQL_AUTH_TYPE_MD5 5
165 #define PGSQL_AUTH_TYPE_SCM 6
166 #define PGSQL_AUTH_TYPE_GSSAPI 7
167 #define PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE 8
168 #define PGSQL_AUTH_TYPE_SSPI 9
169 #define PGSQL_AUTH_TYPE_SASL 10
170 #define PGSQL_AUTH_TYPE_SASL_CONTINUE 11
171 #define PGSQL_AUTH_TYPE_SASL_COMPLETE 12
173 static const value_string auth_types[] = {
174 { PGSQL_AUTH_TYPE_SUCCESS , "Success" },
175 { PGSQL_AUTH_TYPE_KERBEROS4 , "Kerberos V4" },
176 { PGSQL_AUTH_TYPE_KERBEROS5 , "Kerberos V5" },
177 { PGSQL_AUTH_TYPE_PLAINTEXT , "Plaintext password" },
178 { PGSQL_AUTH_TYPE_CRYPT , "crypt()ed password" },
179 { PGSQL_AUTH_TYPE_MD5 , "MD5 password" },
180 { PGSQL_AUTH_TYPE_SCM , "SCM credentials" },
181 { PGSQL_AUTH_TYPE_GSSAPI , "GSSAPI" },
182 { PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE , "GSSAPI/SSPI continue" },
183 { PGSQL_AUTH_TYPE_SSPI , "SSPI" },
184 { PGSQL_AUTH_TYPE_SASL , "SASL" },
185 { PGSQL_AUTH_TYPE_SASL_CONTINUE , "SASL continue" },
186 { PGSQL_AUTH_TYPE_SASL_COMPLETE , "SASL complete" },
187 { 0, NULL }
190 static const value_string status_vals[] = {
191 { 'I', "Idle" },
192 { 'T', "In a transaction" },
193 { 'E', "In a failed transaction" },
194 { 0, NULL }
197 static const value_string format_vals[] = {
198 { 0, "Text" },
199 { 1, "Binary" },
200 { 0, NULL }
203 #define PGSQL_CANCELREQUEST 80877102
204 #define PGSQL_SSLREQUEST 80877103
205 #define PGSQL_GSSENCREQUEST 80877104
207 static const value_string request_code_vals[] = {
208 { PGSQL_CANCELREQUEST, "CancelRequest" },
209 { PGSQL_SSLREQUEST, "SSLRequest" },
210 { PGSQL_GSSENCREQUEST, "GSSENCRequest" },
211 { 0, NULL }
214 static const value_string ssl_response_vals[] = {
215 { 'N', "Unwilling to perform SSL" },
216 { 'S', "Willing to perform SSL" },
217 { 0, NULL }
220 static const value_string gssenc_response_vals[] = {
221 { 'G', "Willing to perform GSSAPI encryption" },
222 { 'N', "Unwilling to perform GSSAPI encryption" },
223 { 0, NULL }
226 static void dissect_pgsql_fe_msg(unsigned char type, unsigned length, tvbuff_t *tvb,
227 int n, proto_tree *tree, packet_info *pinfo,
228 pgsql_conn_data_t *conv_data)
230 unsigned char c;
231 int i, siz;
232 char *s;
233 proto_tree *shrub;
234 int32_t data_length;
235 pgsql_auth_state_t state;
236 tvbuff_t *next_tvb;
237 dissector_handle_t payload_handle;
239 switch (type) {
240 /* Password, SASL or GSSAPI Response, depending on context */
241 case 'p':
242 state = GPOINTER_TO_UINT(wmem_tree_lookup32_le(conv_data->state_tree, pinfo->num));
243 switch(state) {
245 case PGSQL_AUTH_SASL_REQUESTED:
246 /* SASLInitResponse */
247 siz = tvb_strsize(tvb, n);
248 proto_tree_add_item(tree, hf_sasl_auth_mech, tvb, n, siz, ENC_ASCII);
249 n += siz;
250 proto_tree_add_item_ret_int(tree, hf_sasl_auth_data_length, tvb, n, 4, ENC_BIG_ENDIAN, &data_length);
251 n += 4;
252 if (data_length) {
253 proto_tree_add_item(tree, hf_sasl_auth_data, tvb, n, data_length, ENC_NA);
255 break;
257 case PGSQL_AUTH_SASL_CONTINUE:
258 proto_tree_add_item(tree, hf_sasl_auth_data, tvb, n, length-4, ENC_NA);
259 break;
261 case PGSQL_AUTH_GSSAPI_SSPI_DATA:
262 next_tvb = tvb_new_subset_length(tvb, n, length - 4);
263 /* https://www.postgresql.org/docs/current/sspi-auth.html
264 * "PostgreSQL will use SSPI in negotiate mode, which will use
265 * Kerberos when possible and automatically fall back to NTLM
266 * in other cases... When using Kerberos authentication, SSPI
267 * works the same way GSSAPI does."
268 * Assume this means the Kerberos mode for SSPI works like
269 * GSSAPI, and not, say, SPNEGO the way TDS does. (Need
270 * a sample.)
272 if (tvb_strneql(next_tvb, 0, "NTLMSSP", 7) == 0) {
273 payload_handle = ntlmssp_handle;
274 } else {
275 payload_handle = gssapi_handle;
277 n = call_dissector_only(payload_handle, next_tvb, pinfo, tree, NULL);
278 if ((length = tvb_reported_length_remaining(next_tvb, n))) {
279 proto_tree_add_item(tree, hf_gssapi_sspi_data, next_tvb, n, length, ENC_NA);
281 break;
283 default:
284 siz = tvb_strsize(tvb, n);
285 proto_tree_add_item(tree, hf_passwd, tvb, n, siz, ENC_ASCII);
286 break;
288 break;
290 /* Simple query */
291 case 'Q':
292 siz = tvb_strsize(tvb, n);
293 proto_tree_add_item(tree, hf_query, tvb, n, siz, ENC_ASCII);
294 break;
296 /* Parse */
297 case 'P':
298 siz = tvb_strsize(tvb, n);
299 proto_tree_add_item(tree, hf_statement, tvb, n, siz, ENC_ASCII);
300 n += siz;
302 siz = tvb_strsize(tvb, n);
303 proto_tree_add_item(tree, hf_query, tvb, n, siz, ENC_ASCII);
304 n += siz;
306 i = tvb_get_ntohs(tvb, n);
307 shrub = proto_tree_add_subtree_format(tree, tvb, n, 2, ett_values, NULL, "Parameters: %d", i);
308 n += 2;
309 while (i-- > 0) {
310 proto_tree_add_item(shrub, hf_typeoid, tvb, n, 4, ENC_BIG_ENDIAN);
311 n += 4;
313 break;
315 /* Bind */
316 case 'B':
317 siz = tvb_strsize(tvb, n);
318 proto_tree_add_item(tree, hf_portal, tvb, n, siz, ENC_ASCII);
319 n += siz;
321 siz = tvb_strsize(tvb, n);
322 proto_tree_add_item(tree, hf_statement, tvb, n, siz, ENC_ASCII);
323 n += siz;
325 i = tvb_get_ntohs(tvb, n);
326 shrub = proto_tree_add_subtree_format(tree, tvb, n, 2, ett_values, NULL, "Parameter formats: %d", i);
327 n += 2;
328 while (i-- > 0) {
329 proto_tree_add_item(shrub, hf_format, tvb, n, 2, ENC_BIG_ENDIAN);
330 n += 2;
333 i = tvb_get_ntohs(tvb, n);
334 shrub = proto_tree_add_subtree_format(tree, tvb, n, 2, ett_values, NULL, "Parameter values: %d", i);
335 n += 2;
336 while (i-- > 0) {
337 siz = tvb_get_ntohl(tvb, n);
338 proto_tree_add_int(shrub, hf_val_length, tvb, n, 4, siz);
339 n += 4;
340 if (siz > 0) {
341 proto_tree_add_item(shrub, hf_val_data, tvb, n, siz, ENC_NA);
342 n += siz;
346 i = tvb_get_ntohs(tvb, n);
347 shrub = proto_tree_add_subtree_format(tree, tvb, n, 2, ett_values, NULL, "Result formats: %d", i);
348 n += 2;
349 while (i-- > 0) {
350 proto_tree_add_item(shrub, hf_format, tvb, n, 2, ENC_BIG_ENDIAN);
351 n += 2;
353 break;
355 /* Execute */
356 case 'E':
357 siz = tvb_strsize(tvb, n);
358 proto_tree_add_item(tree, hf_portal, tvb, n, siz, ENC_ASCII);
359 n += siz;
361 i = tvb_get_ntohl(tvb, n);
362 if (i == 0)
363 proto_tree_add_uint_format_value(tree, hf_return, tvb, n, 4, i, "all rows");
364 else
365 proto_tree_add_uint_format_value(tree, hf_return, tvb, n, 4, i, "%d rows", i);
366 break;
368 /* Describe, Close */
369 case 'D':
370 case 'C':
371 c = tvb_get_uint8(tvb, n);
372 if (c == 'P')
373 i = hf_portal;
374 else
375 i = hf_statement;
377 n += 1;
378 s = tvb_get_stringz_enc(pinfo->pool, tvb, n, &siz, ENC_ASCII);
379 proto_tree_add_string(tree, i, tvb, n, siz, s);
380 break;
382 /* Messages without a type identifier */
383 case '\0':
384 i = tvb_get_ntohl(tvb, n);
385 n += 4;
386 length -= n;
387 switch (i) {
388 /* Startup message */
389 case 196608:
390 proto_tree_add_item(tree, hf_version_major, tvb, n-4, 2, ENC_BIG_ENDIAN);
391 proto_tree_add_item(tree, hf_version_minor, tvb, n-2, 2, ENC_BIG_ENDIAN);
392 while ((signed)length > 0) {
393 siz = tvb_strsize(tvb, n);
394 length -= siz;
395 if ((signed)length <= 0) {
396 break;
398 proto_tree_add_item(tree, hf_parameter_name, tvb, n, siz, ENC_ASCII);
399 i = tvb_strsize(tvb, n+siz);
400 proto_tree_add_item(tree, hf_parameter_value, tvb, n + siz, i, ENC_ASCII);
401 length -= i;
403 n += siz+i;
404 if (length == 1 && tvb_get_uint8(tvb, n) == 0)
405 break;
407 break;
409 case PGSQL_SSLREQUEST:
410 proto_tree_add_item(tree, hf_request_code, tvb, n-4, 4, ENC_BIG_ENDIAN);
411 /* Next reply will be a single byte. */
412 wmem_tree_insert32(conv_data->state_tree, pinfo->num, GUINT_TO_POINTER(PGSQL_AUTH_SSL_REQUESTED));
413 break;
415 case PGSQL_GSSENCREQUEST:
416 proto_tree_add_item(tree, hf_request_code, tvb, n-4, 4, ENC_BIG_ENDIAN);
417 /* Next reply will be a single byte. */
418 wmem_tree_insert32(conv_data->state_tree, pinfo->num, GUINT_TO_POINTER(PGSQL_AUTH_GSSENC_REQUESTED));
419 break;
421 case PGSQL_CANCELREQUEST:
422 proto_tree_add_item(tree, hf_request_code, tvb, n-4, 4, ENC_BIG_ENDIAN);
423 proto_tree_add_item(tree, hf_pid, tvb, n, 4, ENC_BIG_ENDIAN);
424 proto_tree_add_item(tree, hf_key, tvb, n+4, 4, ENC_BIG_ENDIAN);
425 break;
427 break;
429 /* Copy data */
430 case 'd':
431 proto_tree_add_item(tree, hf_copydata, tvb, n, length-n+1, ENC_NA);
432 break;
434 /* Copy failure */
435 case 'f':
436 siz = tvb_strsize(tvb, n);
437 proto_tree_add_item(tree, hf_error, tvb, n, siz, ENC_ASCII);
438 break;
440 /* Function call */
441 case 'F':
442 proto_tree_add_item(tree, hf_oid, tvb, n, 4, ENC_BIG_ENDIAN);
443 n += 4;
445 i = tvb_get_ntohs(tvb, n);
446 shrub = proto_tree_add_subtree_format(tree, tvb, n, 2, ett_values, NULL, "Parameter formats: %d", i);
447 n += 2;
448 while (i-- > 0) {
449 proto_tree_add_item(shrub, hf_format, tvb, n, 2, ENC_BIG_ENDIAN);
450 n += 2;
453 i = tvb_get_ntohs(tvb, n);
454 shrub = proto_tree_add_subtree_format(tree, tvb, n, 2, ett_values, NULL, "Parameter values: %d", i);
455 n += 2;
456 while (i-- > 0) {
457 siz = tvb_get_ntohl(tvb, n);
458 proto_tree_add_item(shrub, hf_val_length, tvb, n, 4, ENC_BIG_ENDIAN);
459 n += 4;
460 if (siz > 0) {
461 proto_tree_add_item(shrub, hf_val_data, tvb, n, siz, ENC_NA);
462 n += siz;
466 proto_tree_add_item(tree, hf_format, tvb, n, 2, ENC_BIG_ENDIAN);
467 break;
472 static void dissect_pgsql_be_msg(unsigned char type, unsigned length, tvbuff_t *tvb,
473 int n, proto_tree *tree, packet_info *pinfo,
474 pgsql_conn_data_t *conv_data)
476 unsigned char c;
477 int i, siz;
478 char *s, *t;
479 int32_t num_nonsupported_options;
480 proto_item *ti;
481 proto_tree *shrub;
482 uint32_t auth_type;
484 switch (type) {
485 /* Authentication request */
486 case 'R':
487 proto_tree_add_item_ret_uint(tree, hf_authtype, tvb, n, 4, ENC_BIG_ENDIAN, &auth_type);
488 switch (auth_type) {
489 case PGSQL_AUTH_TYPE_CRYPT:
490 case PGSQL_AUTH_TYPE_MD5:
491 n += 4;
492 siz = (auth_type == PGSQL_AUTH_TYPE_CRYPT ? 2 : 4);
493 proto_tree_add_item(tree, hf_salt, tvb, n, siz, ENC_NA);
494 break;
495 case PGSQL_AUTH_TYPE_GSSAPI_SSPI_CONTINUE:
496 proto_tree_add_item(tree, hf_gssapi_sspi_data, tvb, n, length-8, ENC_NA);
497 /* FALLTHROUGH */
498 case PGSQL_AUTH_TYPE_GSSAPI:
499 case PGSQL_AUTH_TYPE_SSPI:
500 wmem_tree_insert32(conv_data->state_tree, pinfo->num, GUINT_TO_POINTER(PGSQL_AUTH_GSSAPI_SSPI_DATA));
501 break;
502 case PGSQL_AUTH_TYPE_SASL:
503 wmem_tree_insert32(conv_data->state_tree, pinfo->num, GUINT_TO_POINTER(PGSQL_AUTH_SASL_REQUESTED));
504 n += 4;
505 while ((unsigned)n < length) {
506 siz = tvb_strsize(tvb, n);
507 proto_tree_add_item(tree, hf_sasl_auth_mech, tvb, n, siz, ENC_ASCII);
508 n += siz;
510 break;
511 case PGSQL_AUTH_TYPE_SASL_CONTINUE:
512 case PGSQL_AUTH_TYPE_SASL_COMPLETE:
513 wmem_tree_insert32(conv_data->state_tree, pinfo->num, GUINT_TO_POINTER(PGSQL_AUTH_SASL_CONTINUE));
514 n += 4;
515 if ((unsigned)n < length) {
516 proto_tree_add_item(tree, hf_sasl_auth_data, tvb, n, length-8, ENC_NA);
518 break;
520 break;
522 /* Key data */
523 case 'K':
524 proto_tree_add_item(tree, hf_pid, tvb, n, 4, ENC_BIG_ENDIAN);
525 proto_tree_add_item(tree, hf_key, tvb, n+4, 4, ENC_BIG_ENDIAN);
526 break;
528 /* Parameter status */
529 case 'S':
530 s = tvb_get_stringz_enc(pinfo->pool, tvb, n, &siz, ENC_ASCII);
531 proto_tree_add_string(tree, hf_parameter_name, tvb, n, siz, s);
532 n += siz;
533 t = tvb_get_stringz_enc(pinfo->pool, tvb, n, &i, ENC_ASCII);
534 proto_tree_add_string(tree, hf_parameter_value, tvb, n, i, t);
535 break;
537 /* Parameter description */
538 case 't':
539 i = tvb_get_ntohs(tvb, n);
540 shrub = proto_tree_add_subtree_format(tree, tvb, n, 2, ett_values, NULL, "Parameters: %d", i);
541 n += 2;
542 while (i-- > 0) {
543 proto_tree_add_item(shrub, hf_typeoid, tvb, n, 4, ENC_BIG_ENDIAN);
544 n += 4;
546 break;
548 /* Row description */
549 case 'T':
550 i = tvb_get_ntohs(tvb, n);
551 ti = proto_tree_add_item(tree, hf_field_count, tvb, n, 2, ENC_BIG_ENDIAN);
552 shrub = proto_item_add_subtree(ti, ett_values);
553 n += 2;
554 while (i-- > 0) {
555 proto_tree *twig;
556 siz = tvb_strsize(tvb, n);
557 ti = proto_tree_add_item(shrub, hf_val_name, tvb, n, siz, ENC_ASCII);
558 twig = proto_item_add_subtree(ti, ett_values);
559 n += siz;
560 proto_tree_add_item(twig, hf_tableoid, tvb, n, 4, ENC_BIG_ENDIAN);
561 n += 4;
562 proto_tree_add_item(twig, hf_val_idx, tvb, n, 2, ENC_BIG_ENDIAN);
563 n += 2;
564 proto_tree_add_item(twig, hf_typeoid, tvb, n, 4, ENC_BIG_ENDIAN);
565 n += 4;
566 proto_tree_add_item(twig, hf_val_length, tvb, n, 2, ENC_BIG_ENDIAN);
567 n += 2;
568 proto_tree_add_item(twig, hf_val_mod, tvb, n, 4, ENC_BIG_ENDIAN);
569 n += 4;
570 proto_tree_add_item(twig, hf_format, tvb, n, 2, ENC_BIG_ENDIAN);
571 n += 2;
573 break;
575 /* Data row */
576 case 'D':
577 i = tvb_get_ntohs(tvb, n);
578 ti = proto_tree_add_item(tree, hf_field_count, tvb, n, 2, ENC_BIG_ENDIAN);
579 shrub = proto_item_add_subtree(ti, ett_values);
580 n += 2;
581 while (i-- > 0) {
582 siz = tvb_get_ntohl(tvb, n);
583 proto_tree_add_int(shrub, hf_val_length, tvb, n, 4, siz);
584 n += 4;
585 if (siz > 0) {
586 proto_tree_add_item(shrub, hf_val_data, tvb, n, siz, ENC_NA);
587 n += siz;
590 break;
592 /* Command completion */
593 case 'C':
594 siz = tvb_strsize(tvb, n);
595 proto_tree_add_item(tree, hf_tag, tvb, n, siz, ENC_ASCII);
596 break;
598 /* Ready */
599 case 'Z':
600 proto_tree_add_item(tree, hf_status, tvb, n, 1, ENC_BIG_ENDIAN);
601 break;
603 /* Error, Notice */
604 case 'E':
605 case 'N':
606 length -= 4;
607 while ((signed)length > 0) {
608 c = tvb_get_uint8(tvb, n);
609 if (c == '\0')
610 break;
611 --length;
612 s = tvb_get_stringz_enc(pinfo->pool, tvb, n+1, &siz, ENC_ASCII);
613 i = hf_text;
614 switch (c) {
615 case 'S': i = hf_severity; break;
616 case 'C': i = hf_code; break;
617 case 'M': i = hf_message; break;
618 case 'D': i = hf_detail; break;
619 case 'H': i = hf_hint; break;
620 case 'P': i = hf_position; break;
621 case 'p': i = hf_internal_position; break;
622 case 'q': i = hf_internal_query; break;
623 case 'W': i = hf_where; break;
624 case 's': i = hf_schema_name; break;
625 case 't': i = hf_table_name; break;
626 case 'c': i = hf_column_name; break;
627 case 'd': i = hf_type_name; break;
628 case 'n': i = hf_constraint_name; break;
629 case 'F': i = hf_file; break;
630 case 'L': i = hf_line; break;
631 case 'R': i = hf_routine; break;
633 proto_tree_add_string(tree, i, tvb, n, siz+1, s);
634 length -= siz+1;
635 n += siz+1;
637 break;
639 /* NOTICE response */
640 case 'A':
641 proto_tree_add_item(tree, hf_pid, tvb, n, 4, ENC_BIG_ENDIAN);
642 n += 4;
643 siz = tvb_strsize(tvb, n);
644 proto_tree_add_item(tree, hf_condition, tvb, n, siz, ENC_ASCII);
645 n += siz;
646 siz = tvb_strsize(tvb, n);
647 if (siz > 1)
648 proto_tree_add_item(tree, hf_text, tvb, n, siz, ENC_ASCII);
649 break;
651 /* Copy in/out */
652 case 'G':
653 case 'H':
654 proto_tree_add_item(tree, hf_format, tvb, n, 1, ENC_BIG_ENDIAN);
655 n += 1;
656 i = tvb_get_ntohs(tvb, n);
657 shrub = proto_tree_add_subtree_format(tree, tvb, n, 2, ett_values, NULL, "Columns: %d", i);
658 n += 2;
659 while (i-- > 2) {
660 proto_tree_add_item(shrub, hf_format, tvb, n, 2, ENC_BIG_ENDIAN);
661 n += 2;
663 break;
665 /* Copy data */
666 case 'd':
667 proto_tree_add_item(tree, hf_copydata, tvb, n, length-n+1, ENC_NA);
668 break;
670 /* Function call response */
671 case 'V':
672 siz = tvb_get_ntohl(tvb, n);
673 proto_tree_add_int(tree, hf_val_length, tvb, n, 4, siz);
674 if (siz > 0)
675 proto_tree_add_item(tree, hf_val_data, tvb, n+4, siz, ENC_NA);
676 break;
678 /* Negotiate Protocol Version */
679 case 'v':
680 proto_tree_add_item(tree, hf_supported_minor_version, tvb, n, 4, ENC_BIG_ENDIAN);
681 n += 4;
682 proto_tree_add_item_ret_int(tree, hf_number_nonsupported_options, tvb, n, 4, ENC_BIG_ENDIAN, &num_nonsupported_options);
683 n += 4;
684 while (num_nonsupported_options > 0) {
685 siz = tvb_strsize(tvb, n);
686 proto_tree_add_item(tree, hf_nonsupported_option, tvb, n, siz, ENC_ASCII);
687 n += siz;
688 num_nonsupported_options--;
690 break;
694 /* This function is called by tcp_dissect_pdus() to find the size of the
695 message starting at tvb[offset]. */
696 static unsigned
697 pgsql_length(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
699 int n = 0;
700 unsigned char type;
701 unsigned length;
703 /* The length is either the four bytes after the type, or, if the
704 type is 0, the first four bytes. */
705 type = tvb_get_uint8(tvb, offset);
706 if (type != '\0')
707 n = 1;
708 length = tvb_get_ntohl(tvb, offset+n);
709 return length+n;
712 /* This function is called by tcp_dissect_pdus() to find the size of the
713 wrapped GSS-API message starting at tvb[offset] whe. */
714 static unsigned
715 pgsql_gssapi_length(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
717 /* The length of the GSS-API message is the first four bytes, and does
718 * not include the 4 byte length (the gss_wrap). */
719 return tvb_get_ntohl(tvb, offset) + 4;
723 /* This function is responsible for dissecting a single message. */
725 static int
726 dissect_pgsql_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
728 proto_item *ti, *hidden_item;
729 proto_tree *ptree;
730 conversation_t *conversation;
731 pgsql_conn_data_t *conn_data;
732 pgsql_auth_state_t state;
734 int n;
735 unsigned char type;
736 const char *typestr;
737 unsigned length;
738 bool fe;
740 conversation = find_or_create_conversation(pinfo);
741 conn_data = (pgsql_conn_data_t *)conversation_get_proto_data(conversation, proto_pgsql);
742 if (!conn_data) {
743 conn_data = wmem_new(wmem_file_scope(), pgsql_conn_data_t);
744 conn_data->state_tree = wmem_tree_new(wmem_file_scope());
745 conn_data->server_port = pinfo->match_uint;
746 wmem_tree_insert32(conn_data->state_tree, pinfo->num, GUINT_TO_POINTER(PGSQL_AUTH_STATE_NONE));
747 conversation_add_proto_data(conversation, proto_pgsql, conn_data);
750 fe = (conn_data->server_port == pinfo->destport);
752 n = 0;
753 type = tvb_get_uint8(tvb, 0);
754 if (type != '\0')
755 n += 1;
756 length = tvb_get_ntohl(tvb, n);
758 /* This is like specifying VALS(messages) for hf_type, which we can't do
759 directly because of messages without type bytes, and because the type
760 interpretation depends on fe. */
761 if (fe) {
762 /* There are a few frontend messages that have no leading type byte.
763 We identify them by the fact that the first byte of their length
764 must be zero, and that the next four bytes are a unique tag. */
765 if (type == '\0') {
766 unsigned tag = tvb_get_ntohl(tvb, 4);
768 if (length == 16 && tag == PGSQL_CANCELREQUEST)
769 typestr = "Cancel request";
770 else if (length == 8 && tag == PGSQL_SSLREQUEST)
771 typestr = "SSL request";
772 else if (length == 8 && tag == PGSQL_GSSENCREQUEST)
773 typestr = "GSS encrypt request";
774 else if (tag == 196608)
775 typestr = "Startup message";
776 else
777 typestr = "Unknown";
778 } else if (type == 'p') {
779 state = GPOINTER_TO_UINT(wmem_tree_lookup32_le(conn_data->state_tree, pinfo->num));
780 switch (state) {
781 case PGSQL_AUTH_SASL_REQUESTED:
782 typestr = "SASLInitialResponse message";
783 break;
784 case PGSQL_AUTH_SASL_CONTINUE:
785 typestr = "SASLResponse message";
786 break;
787 case PGSQL_AUTH_GSSAPI_SSPI_DATA:
788 typestr = "GSSResponse message";
789 break;
790 default:
791 typestr = "Password message";
792 break;
794 } else
795 typestr = val_to_str_const(type, fe_messages, "Unknown");
797 else {
798 typestr = val_to_str_const(type, be_messages, "Unknown");
801 /* This is a terrible hack. It makes the "Info" column reflect
802 the contents of every message in a TCP packet. Could it be
803 done any better? */
804 col_append_fstr(pinfo->cinfo, COL_INFO, "%s%c",
805 ( first_message ? "" : "/" ), g_ascii_isprint(type) ? type : '?');
806 first_message = false;
809 ti = proto_tree_add_item(tree, proto_pgsql, tvb, 0, -1, ENC_NA);
810 ptree = proto_item_add_subtree(ti, ett_pgsql);
812 n = 1;
813 if (type == '\0')
814 n = 0;
815 proto_tree_add_string(ptree, hf_type, tvb, 0, n, typestr);
816 proto_tree_add_item(ptree, hf_length, tvb, n, 4, ENC_BIG_ENDIAN);
817 hidden_item = proto_tree_add_boolean(ptree, hf_frontend, tvb, 0, 0, fe);
818 proto_item_set_hidden(hidden_item);
819 n += 4;
821 if (fe)
822 dissect_pgsql_fe_msg(type, length, tvb, n, ptree, pinfo, conn_data);
823 else
824 dissect_pgsql_be_msg(type, length, tvb, n, ptree, pinfo, conn_data);
827 return tvb_captured_length(tvb);
830 static int
831 dissect_pgsql_gssapi_wrap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
833 proto_item *ti;
834 proto_tree *ptree;
836 conversation_t *conversation;
837 pgsql_conn_data_t *conn_data;
839 conversation = find_or_create_conversation(pinfo);
840 conn_data = (pgsql_conn_data_t *)conversation_get_proto_data(conversation, proto_pgsql);
842 if (!conn_data) {
843 /* This shouldn't happen. */
844 conn_data = wmem_new0(wmem_file_scope(), pgsql_conn_data_t);
845 conn_data->state_tree = wmem_tree_new(wmem_file_scope());
846 conn_data->server_port = pinfo->match_uint;
847 wmem_tree_insert32(conn_data->state_tree, pinfo->num, GUINT_TO_POINTER(PGSQL_AUTH_GSSAPI_SSPI_DATA));
848 conversation_add_proto_data(conversation, proto_pgsql, conn_data);
851 bool fe = (pinfo->destport == conn_data->server_port);
853 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGSQL");
854 col_set_str(pinfo->cinfo, COL_INFO,
855 fe ? ">" : "<");
857 ti = proto_tree_add_item(tree, proto_pgsql, tvb, 0, -1, ENC_NA);
858 ptree = proto_item_add_subtree(ti, ett_pgsql);
860 proto_tree_add_string(ptree, hf_type, tvb, 0, 0, "GSS-API encrypted message");
861 proto_tree_add_item(ptree, hf_length, tvb, 0, 4, ENC_BIG_ENDIAN);
863 gssapi_encrypt_info_t encrypt;
864 memset(&encrypt, 0, sizeof(encrypt));
865 encrypt.decrypt_gssapi_tvb = DECRYPT_GSSAPI_NORMAL;
867 int ver_len;
868 tvbuff_t *gssapi_tvb = tvb_new_subset_remaining(tvb, 4);
870 ver_len = call_dissector_with_data(gssapi_handle, gssapi_tvb, pinfo, ptree, &encrypt);
871 if (ver_len == 0) {
872 /* GSS-API couldn't do anything with it. */
873 return tvb_captured_length(tvb);
875 if (encrypt.gssapi_data_encrypted) {
876 if (encrypt.gssapi_decrypted_tvb) {
877 tvbuff_t *decr_tvb = encrypt.gssapi_decrypted_tvb;
878 add_new_data_source(pinfo, encrypt.gssapi_decrypted_tvb, "Decrypted GSS-API");
879 dissect_pgsql_msg(decr_tvb, pinfo, ptree, data);
880 } else {
881 /* Encrypted but couldn't be decrypted. */
882 proto_tree_add_item(ptree, hf_gssapi_encrypted_payload, gssapi_tvb, ver_len, -1, ENC_NA);
884 } else {
885 /* No encrypted (sealed) payload. If any bytes are left, that is
886 * signed-only payload. */
887 tvbuff_t *plain_tvb;
888 if (encrypt.gssapi_decrypted_tvb) {
889 plain_tvb = encrypt.gssapi_decrypted_tvb;
890 } else {
891 plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
893 if (tvb_reported_length(plain_tvb)) {
894 dissect_pgsql_msg(plain_tvb, pinfo, ptree, data);
897 return tvb_captured_length(tvb);
900 static int
901 dissect_pgsql_gssapi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
903 tcp_dissect_pdus(tvb, pinfo, tree, pgsql_desegment, 4,
904 pgsql_gssapi_length, dissect_pgsql_gssapi_wrap, data);
905 return tvb_captured_length(tvb);
908 /* This function is called once per TCP packet. It sets COL_PROTOCOL and
909 * identifies FE/BE messages by adding a ">" or "<" to COL_INFO. Then it
910 * arranges for each message to be dissected individually. */
912 static int
913 dissect_pgsql(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
915 proto_item *ti;
916 proto_tree *ptree;
917 conversation_t *conversation;
918 pgsql_conn_data_t *conn_data;
919 pgsql_auth_state_t state;
921 first_message = true;
923 conversation = find_or_create_conversation(pinfo);
924 conn_data = (pgsql_conn_data_t *)conversation_get_proto_data(conversation, proto_pgsql);
926 bool fe = (pinfo->match_uint == pinfo->destport);
928 if (fe && tvb_get_uint8(tvb, 0) == 0x16 &&
929 (!conn_data || wmem_tree_lookup32_le(conn_data->state_tree, pinfo->num) == NULL))
931 /* This is the first message in the conversation, and it looks
932 * like a TLS handshake. Assume the client is performing
933 * "direct SSL" negotiation.
935 tls_set_appdata_dissector(tls_handle, pinfo, pgsql_handle);
938 if (!tvb_ascii_isprint(tvb, 0, 1) && tvb_get_uint8(tvb, 0) != '\0') {
939 /* Doesn't look like the start of a PostgreSQL packet. Have we
940 * seen Postgres yet?
942 if (!conn_data || wmem_tree_lookup32_le(conn_data->state_tree, pinfo->num) == NULL) {
943 /* No. Reject. This might be PostgreSQL over TLS and we missed
944 * the start of the transaction. The TLS dissector should get
945 * a chance.
947 return 0;
949 /* Was there segmentation, and we lost a packet or were out of
950 * order without out of order processing, or we couldn't do
951 * desegmentation of a segment because of a bad checksum?
952 * XXX: Should we call this Continuation Data if this happens,
953 * so we don't send it to tcp_dissect_pdus()?
957 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGSQL");
958 col_set_str(pinfo->cinfo, COL_INFO,
959 fe ? ">" : "<");
961 if (conn_data && !fe) {
962 state = GPOINTER_TO_UINT(wmem_tree_lookup32_le(conn_data->state_tree, pinfo->num));
963 if (state == PGSQL_AUTH_SSL_REQUESTED) {
964 /* Response to SSLRequest. */
965 wmem_tree_insert32(conn_data->state_tree, pinfo->num + 1, GUINT_TO_POINTER(PGSQL_AUTH_STATE_NONE));
966 ti = proto_tree_add_item(tree, proto_pgsql, tvb, 0, -1, ENC_NA);
967 ptree = proto_item_add_subtree(ti, ett_pgsql);
968 proto_tree_add_string(ptree, hf_type, tvb, 0, 0, "SSL response");
969 proto_tree_add_item(ptree, hf_ssl_response, tvb, 0, 1, ENC_NA);
970 switch (tvb_get_uint8(tvb, 0)) {
971 case 'S': /* Willing to perform SSL */
972 /* Next packet will start using SSL. */
973 ssl_starttls_ack(tls_handle, pinfo, pgsql_handle);
974 break;
975 case 'E': /* ErrorResponse when server does not support SSL. */
976 /* Process normally. */
977 tcp_dissect_pdus(tvb, pinfo, tree, pgsql_desegment, 5,
978 pgsql_length, dissect_pgsql_msg, data);
979 break;
980 case 'N': /* Unwilling to perform SSL */
981 default: /* Unexpected response. */
982 /* TODO: maybe add expert info here? */
983 break;
985 /* XXX: If it's anything other than 'E', a length of more
986 * than one character is unexpected and should possibly have
987 * an expert info (possible MitM:
988 * https://www.postgresql.org/support/security/CVE-2021-23222/ )
990 return tvb_captured_length(tvb);
991 } else if (state == PGSQL_AUTH_GSSENC_REQUESTED) {
992 /* Response to GSSENCRequest. */
993 wmem_tree_insert32(conn_data->state_tree, pinfo->num + 1, GUINT_TO_POINTER(PGSQL_AUTH_STATE_NONE));
994 ti = proto_tree_add_item(tree, proto_pgsql, tvb, 0, -1, ENC_NA);
995 ptree = proto_item_add_subtree(ti, ett_pgsql);
996 proto_tree_add_string(ptree, hf_type, tvb, 0, 0, "GSS encrypt response");
997 proto_tree_add_item(ptree, hf_gssenc_response, tvb, 0, 1, ENC_NA);
998 switch (tvb_get_uint8(tvb, 0)) {
999 case 'E': /* ErrorResponse; server does not support GSSAPI. */
1000 /* Process normally. */
1001 tcp_dissect_pdus(tvb, pinfo, tree, pgsql_desegment, 5,
1002 pgsql_length, dissect_pgsql_msg, data);
1003 break;
1004 case 'G': /* Willing to perform GSSAPI Enc */
1005 wmem_tree_insert32(conn_data->state_tree, pinfo->num + 1, GUINT_TO_POINTER(PGSQL_AUTH_GSSAPI_SSPI_DATA));
1006 conversation_set_dissector_from_frame_number(conversation, pinfo->num + 1, pgsql_gssapi_handle);
1007 break;
1008 case 'N': /* Unwilling to perform GSSAPI Enc */
1009 default: /* Unexpected response. */
1010 /* TODO: maybe add expert info here? */
1011 break;
1013 return tvb_captured_length(tvb);
1017 tcp_dissect_pdus(tvb, pinfo, tree, pgsql_desegment, 5,
1018 pgsql_length, dissect_pgsql_msg, data);
1019 return tvb_captured_length(tvb);
1022 void
1023 proto_register_pgsql(void)
1025 static hf_register_info hf[] = {
1026 { &hf_frontend,
1027 { "Frontend", "pgsql.frontend", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1028 "True for messages from the frontend, false otherwise.",
1029 HFILL }
1031 { &hf_type,
1032 { "Type", "pgsql.type", FT_STRING, BASE_NONE, NULL, 0,
1033 "A one-byte message type identifier.", HFILL }
1035 { &hf_length,
1036 { "Length", "pgsql.length", FT_UINT32, BASE_DEC, NULL, 0,
1037 "The length of the message (not including the type).",
1038 HFILL }
1040 { &hf_version_major,
1041 { "Protocol major version", "pgsql.version_major", FT_UINT16, BASE_DEC, NULL, 0,
1042 NULL, HFILL }
1044 { &hf_version_minor,
1045 { "Protocol minor version", "pgsql.version_minor", FT_UINT16, BASE_DEC, NULL, 0,
1046 NULL, HFILL }
1048 { &hf_request_code,
1049 { "Request code", "pgsql.request_code", FT_UINT32, BASE_DEC,
1050 VALS(request_code_vals), 0, NULL, HFILL }
1052 { &hf_supported_minor_version,
1053 { "Supported minor version", "pgsql.version_supported_minor", FT_UINT32, BASE_DEC, NULL, 0,
1054 "Newest minor protocol version supported by the server for the major protocol version requested by the client.", HFILL }
1056 { &hf_number_nonsupported_options,
1057 { "Number nonsupported options", "pgsql.number_nonsupported_options", FT_INT32, BASE_DEC, NULL, 0,
1058 NULL, HFILL }
1060 { &hf_nonsupported_option,
1061 { "Nonsupported option", "pgsql.nonsupported_option", FT_STRINGZ, BASE_NONE, NULL, 0,
1062 NULL, HFILL }
1064 { &hf_parameter_name,
1065 { "Parameter name", "pgsql.parameter_name", FT_STRINGZ,
1066 BASE_NONE, NULL, 0, "The name of a database parameter.",
1067 HFILL }
1069 { &hf_parameter_value,
1070 { "Parameter value", "pgsql.parameter_value", FT_STRINGZ,
1071 BASE_NONE, NULL, 0, "The value of a database parameter.",
1072 HFILL }
1074 { &hf_query,
1075 { "Query", "pgsql.query", FT_STRINGZ, BASE_NONE, NULL, 0,
1076 "A query string.", HFILL }
1078 { &hf_passwd,
1079 { "Password", "pgsql.password", FT_STRINGZ, BASE_NONE, NULL, 0,
1080 "A password.", HFILL }
1082 { &hf_authtype,
1083 { "Authentication type", "pgsql.authtype", FT_UINT32, BASE_DEC,
1084 VALS(auth_types), 0,
1085 "The type of authentication requested by the backend.", HFILL }
1087 { &hf_salt,
1088 { "Salt value", "pgsql.salt", FT_BYTES, BASE_NONE, NULL, 0,
1089 "The salt to use while encrypting a password.", HFILL }
1091 { &hf_gssapi_sspi_data,
1092 { "GSSAPI or SSPI authentication data", "pgsql.auth.gssapi_sspi.data", FT_BYTES, BASE_NONE, NULL, 0,
1093 NULL, HFILL }
1095 { &hf_sasl_auth_mech,
1096 { "SASL authentication mechanism", "pgsql.auth.sasl.mech", FT_STRINGZ, BASE_NONE, NULL, 0,
1097 NULL, HFILL }
1099 { &hf_sasl_auth_data_length,
1100 { "SASL authentication data length", "pgsql.auth.sasl.data.length", FT_INT32, BASE_DEC, NULL, 0,
1101 NULL, HFILL }
1103 { &hf_sasl_auth_data,
1104 { "SASL authentication data", "pgsql.auth.sasl.data", FT_BYTES, BASE_NONE, NULL, 0,
1105 NULL, HFILL }
1107 { &hf_statement,
1108 { "Statement", "pgsql.statement", FT_STRINGZ, BASE_NONE, NULL, 0,
1109 "The name of a prepared statement.", HFILL }
1111 { &hf_portal,
1112 { "Portal", "pgsql.portal", FT_STRINGZ, BASE_NONE, NULL, 0,
1113 "The name of a portal.", HFILL }
1115 { &hf_return,
1116 { "Returns", "pgsql.returns", FT_UINT32, BASE_DEC,
1117 NULL, 0,
1118 NULL, HFILL }
1120 { &hf_tag,
1121 { "Tag", "pgsql.tag", FT_STRINGZ, BASE_NONE, NULL, 0,
1122 "A completion tag.", HFILL }
1124 { &hf_status,
1125 { "Status", "pgsql.status", FT_UINT8, BASE_DEC, VALS(status_vals),
1126 0, "The transaction status of the backend.", HFILL }
1128 { &hf_copydata,
1129 { "Copy data", "pgsql.copydata", FT_BYTES, BASE_NONE, NULL, 0,
1130 "Data sent following a Copy-in or Copy-out response.", HFILL }
1132 { &hf_error,
1133 { "Error", "pgsql.error", FT_STRINGZ, BASE_NONE, NULL, 0,
1134 "An error message.", HFILL }
1136 { &hf_pid,
1137 { "PID", "pgsql.pid", FT_UINT32, BASE_DEC, NULL, 0,
1138 "The process ID of a backend.", HFILL }
1140 { &hf_key,
1141 { "Key", "pgsql.key", FT_UINT32, BASE_DEC, NULL, 0,
1142 "The secret key used by a particular backend.", HFILL }
1144 { &hf_condition,
1145 { "Condition", "pgsql.condition", FT_STRINGZ, BASE_NONE, NULL, 0,
1146 "The name of a NOTIFY condition.", HFILL }
1148 { &hf_text,
1149 { "Text", "pgsql.text", FT_STRINGZ, BASE_NONE, NULL, 0,
1150 "Text from the backend.", HFILL }
1152 { &hf_tableoid,
1153 { "Table OID", "pgsql.oid.table", FT_UINT32, BASE_DEC, NULL, 0,
1154 "The object identifier of a table.", HFILL }
1156 { &hf_typeoid,
1157 { "Type OID", "pgsql.oid.type", FT_UINT32, BASE_DEC, NULL, 0,
1158 "The object identifier of a type.", HFILL }
1160 { &hf_oid,
1161 { "OID", "pgsql.oid", FT_UINT32, BASE_DEC, NULL, 0,
1162 "An object identifier.", HFILL }
1164 { &hf_format,
1165 { "Format", "pgsql.format", FT_UINT16, BASE_DEC, VALS(format_vals),
1166 0, "A format specifier.", HFILL }
1168 { &hf_field_count,
1169 { "Field count", "pgsql.field.count", FT_UINT16, BASE_DEC, NULL, 0,
1170 "The number of fields within a row.", HFILL }
1172 { &hf_val_name,
1173 { "Column name", "pgsql.col.name", FT_STRINGZ, BASE_NONE, NULL, 0,
1174 "The name of a column.", HFILL }
1176 { &hf_val_idx,
1177 { "Column index", "pgsql.col.index", FT_UINT32, BASE_DEC, NULL, 0,
1178 "The position of a column within a row.", HFILL }
1180 { &hf_val_length,
1181 { "Column length", "pgsql.val.length", FT_INT32, BASE_DEC, NULL, 0,
1182 "The length of a parameter value, in bytes. -1 means NULL.",
1183 HFILL }
1185 { &hf_val_data,
1186 { "Data", "pgsql.val.data", FT_BYTES, BASE_NONE, NULL, 0,
1187 "Parameter data.", HFILL }
1189 { &hf_val_mod,
1190 { "Type modifier", "pgsql.col.typemod", FT_INT32, BASE_DEC, NULL, 0,
1191 "The type modifier for a column.", HFILL }
1193 { &hf_severity,
1194 { "Severity", "pgsql.severity", FT_STRINGZ, BASE_NONE, NULL, 0,
1195 "Message severity.", HFILL }
1197 { &hf_code,
1198 { "Code", "pgsql.code", FT_STRINGZ, BASE_NONE, NULL, 0,
1199 "SQLState code.", HFILL }
1201 { &hf_message,
1202 { "Message", "pgsql.message", FT_STRINGZ, BASE_NONE, NULL, 0,
1203 "Error message.", HFILL }
1205 { &hf_detail,
1206 { "Detail", "pgsql.detail", FT_STRINGZ, BASE_NONE, NULL, 0,
1207 "Detailed error message.", HFILL }
1209 { &hf_hint,
1210 { "Hint", "pgsql.hint", FT_STRINGZ, BASE_NONE, NULL, 0,
1211 "A suggestion to resolve an error.", HFILL }
1213 { &hf_position,
1214 { "Position", "pgsql.position", FT_STRINGZ, BASE_NONE, NULL, 0,
1215 "The index of the error within the query string.", HFILL }
1217 { &hf_internal_position,
1218 { "Position (Internal)", "pgsql.internal_position", FT_STRINGZ, BASE_NONE, NULL, 0,
1219 "The index of the error within the internally-generated query string.", HFILL }
1221 { &hf_internal_query,
1222 { "Query (Internal)", "pgsql.internal_query", FT_STRINGZ, BASE_NONE, NULL, 0,
1223 "The internally-generated query string", HFILL }
1225 { &hf_where,
1226 { "Context", "pgsql.where", FT_STRINGZ, BASE_NONE, NULL, 0,
1227 "The context in which an error occurred.", HFILL }
1229 { &hf_schema_name,
1230 { "Schema", "pgsql.schema_name", FT_STRINGZ, BASE_NONE, NULL, 0,
1231 "The schema with which an error is associated.", HFILL }
1233 { &hf_table_name,
1234 { "Table", "pgsql.table_name", FT_STRINGZ, BASE_NONE, NULL, 0,
1235 "The table with which an error is associated.", HFILL }
1237 { &hf_column_name,
1238 { "Column", "pgsql.column_name", FT_STRINGZ, BASE_NONE, NULL, 0,
1239 "The column with which an error is associated.", HFILL }
1241 { &hf_type_name,
1242 { "Type", "pgsql.type_name", FT_STRINGZ, BASE_NONE, NULL, 0,
1243 "The date type with which an error is associated.", HFILL }
1245 { &hf_constraint_name,
1246 { "Constraint", "pgsql.constraint_name", FT_STRINGZ, BASE_NONE, NULL, 0,
1247 "The constraint with which an error is associated.", HFILL }
1249 { &hf_file,
1250 { "File", "pgsql.file", FT_STRINGZ, BASE_NONE, NULL, 0,
1251 "The source-code file where an error was reported.", HFILL }
1253 { &hf_line,
1254 { "Line", "pgsql.line", FT_STRINGZ, BASE_NONE, NULL, 0,
1255 "The line number on which an error was reported.", HFILL }
1257 { &hf_routine,
1258 { "Routine", "pgsql.routine", FT_STRINGZ, BASE_NONE, NULL, 0,
1259 "The routine that reported an error.", HFILL }
1261 { &hf_ssl_response,
1262 { "SSL Response", "pgsql.ssl_response", FT_CHAR, BASE_HEX,
1263 VALS(ssl_response_vals), 0, NULL, HFILL }
1265 { &hf_gssenc_response,
1266 { "GSSAPI Encrypt Response", "pgsql.gssenc_response", FT_CHAR,
1267 BASE_HEX, VALS(gssenc_response_vals), 0, NULL, HFILL }
1269 { &hf_gssapi_encrypted_payload,
1270 { "GSS-API encrypted payload", "pgsql.gssapi.encrypted_payload", FT_BYTES, BASE_NONE, NULL, 0,
1271 NULL, HFILL }
1275 static int *ett[] = {
1276 &ett_pgsql,
1277 &ett_values
1280 proto_pgsql = proto_register_protocol("PostgreSQL", "PGSQL", "pgsql");
1281 pgsql_handle = register_dissector("pgsql", dissect_pgsql, proto_pgsql);
1282 proto_register_field_array(proto_pgsql, hf, array_length(hf));
1283 proto_register_subtree_array(ett, array_length(ett));
1285 /* Unfortunately there's no way to set up a GSS-API conversation
1286 * instructing the GSS-API dissector to use our wrap handle; that
1287 * only works for protocols that have an OID and that begin the
1288 * GSS-API conversation by sending that OID.
1290 pgsql_gssapi_handle = register_dissector("pgsql.gssapi", dissect_pgsql_gssapi, proto_pgsql);
1293 void
1294 proto_reg_handoff_pgsql(void)
1296 dissector_add_uint_with_preference("tcp.port", PGSQL_PORT, pgsql_handle);
1298 tls_handle = find_dissector_add_dependency("tls", proto_pgsql);
1299 gssapi_handle = find_dissector_add_dependency("gssapi", proto_pgsql);
1300 ntlmssp_handle = find_dissector_add_dependency("ntlmssp", proto_pgsql);
1304 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1306 * Local variables:
1307 * c-basic-offset: 4
1308 * tab-width: 8
1309 * indent-tabs-mode: nil
1310 * End:
1312 * vi: set shiftwidth=4 tabstop=8 expandtab:
1313 * :indentSize=4:tabSize=8:noTabs=true: