wireshark/epan/dissectors/packet-cups.c
João Valverde 19dcb725b6 epan: Remove STR_ASCII and STR_UNICODE
These display bases work to replace unprintable characters so the
name is a misnomer. In addition they are the same option and this
display behaviour is not something that is configurable.

This does not affect encodings because all our internal text strings
need to be valid UTF-8 and the source encoding is specified using
ENC_*.

Remove the assertion for valid UTF-8 in proto.c because
tvb_get_*_string() must return a valid UTF-8 string, always, and we
don't need to assert that, it is expensive.
2021-12-03 04:35:56 +00:00

409 lines
15 KiB
C

/* packet-cups.c
* Routines for Common Unix Printing System (CUPS) Browsing Protocol
* packet disassembly for the Wireshark network traffic analyzer.
*
* Charles Levert <charles@comm.polymtl.ca>
* Copyright 2001 Charles Levert
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
*/
#include "config.h"
#include <epan/packet.h>
#include <wsutil/str_util.h>
/**********************************************************************/
void proto_register_cups(void);
void proto_reg_handoff_cups(void);
/* From cups/cups.h, GNU GPL, Copyright 1997-2001 by Easy Software Products. */
typedef guint32 cups_ptype_t; /**** Printer Type/Capability Bits ****/
enum /* Not a typedef'd enum so we can OR */
{
CUPS_PRINTER_LOCAL = 0x0000, /* Local printer or class */
CUPS_PRINTER_CLASS = 0x0001, /* Printer class */
CUPS_PRINTER_REMOTE = 0x0002, /* Remote printer or class */
CUPS_PRINTER_BW = 0x0004, /* Can do B&W printing */
CUPS_PRINTER_COLOR = 0x0008, /* Can do color printing */
CUPS_PRINTER_DUPLEX = 0x0010, /* Can do duplexing */
CUPS_PRINTER_STAPLE = 0x0020, /* Can staple output */
CUPS_PRINTER_COPIES = 0x0040, /* Can do copies */
CUPS_PRINTER_COLLATE = 0x0080, /* Can collage copies */
CUPS_PRINTER_PUNCH = 0x0100, /* Can punch output */
CUPS_PRINTER_COVER = 0x0200, /* Can cover output */
CUPS_PRINTER_BIND = 0x0400, /* Can bind output */
CUPS_PRINTER_SORT = 0x0800, /* Can sort output */
CUPS_PRINTER_SMALL = 0x1000, /* Can do Letter/Legal/A4 */
CUPS_PRINTER_MEDIUM = 0x2000, /* Can do Tabloid/B/C/A3/A2 */
CUPS_PRINTER_LARGE = 0x4000, /* Can do D/E/A1/A0 */
CUPS_PRINTER_VARIABLE = 0x8000, /* Can do variable sizes */
CUPS_PRINTER_IMPLICIT = 0x10000, /* Implicit class */
CUPS_PRINTER_DEFAULT = 0x20000, /* Default printer on network */
CUPS_PRINTER_OPTIONS = 0xfffc /* ~(CLASS | REMOTE | IMPLICIT) */
};
/* End insert from cups/cups.h */
typedef enum _cups_state {
CUPS_IDLE = 3,
CUPS_PROCESSING,
CUPS_STOPPED
} cups_state_t;
static const value_string cups_state_values[] = {
{ CUPS_IDLE, "idle" },
{ CUPS_PROCESSING, "processing" },
{ CUPS_STOPPED, "stopped" },
{ 0, NULL }
};
static const true_false_string tfs_implicit_explicit = { "Implicit class", "Explicit class" };
static const true_false_string tfs_printer_class = { "Printer class", "Single printer" };
static int proto_cups = -1;
static int hf_cups_ptype = -1;
static int hf_cups_ptype_default = -1;
static int hf_cups_ptype_implicit = -1;
static int hf_cups_ptype_variable = -1;
static int hf_cups_ptype_large = -1;
static int hf_cups_ptype_medium = -1;
static int hf_cups_ptype_small = -1;
static int hf_cups_ptype_sort = -1;
static int hf_cups_ptype_bind = -1;
static int hf_cups_ptype_cover = -1;
static int hf_cups_ptype_punch = -1;
static int hf_cups_ptype_collate = -1;
static int hf_cups_ptype_copies = -1;
static int hf_cups_ptype_staple = -1;
static int hf_cups_ptype_duplex = -1;
static int hf_cups_ptype_color = -1;
static int hf_cups_ptype_bw = -1;
static int hf_cups_ptype_remote = -1;
static int hf_cups_ptype_class = -1;
static int hf_cups_state = -1;
static int hf_cups_uri = -1;
static int hf_cups_location = -1;
static int hf_cups_information = -1;
static int hf_cups_make_model = -1;
static gint ett_cups = -1;
static gint ett_cups_ptype = -1;
/* patterns used for tvb_ws_mempbrk_pattern_guint8 */
static ws_mempbrk_pattern pbrk_whitespace;
/* This protocol is heavily related to IPP, but it is CUPS-specific
and non-standard. */
#define UDP_PORT_CUPS 631
#define PROTO_TAG_CUPS "CUPS"
static guint get_hex_uint(tvbuff_t *tvb, gint offset, gint *next_offset);
static gboolean skip_space(tvbuff_t *tvb, gint offset, gint *next_offset);
static const guint8* get_quoted_string(tvbuff_t *tvb, gint offset,
gint *next_offset, guint *len);
static const guint8* get_unquoted_string(tvbuff_t *tvb, gint offset,
gint *next_offset, guint *len);
/**********************************************************************/
static int
dissect_cups(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_tree *cups_tree = NULL;
proto_tree *ptype_subtree = NULL;
proto_item *ti = NULL;
gint offset = 0;
gint next_offset;
guint len;
const guint8 *str;
cups_ptype_t ptype;
unsigned int state;
col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_CUPS);
col_clear(pinfo->cinfo, COL_INFO);
ti = proto_tree_add_item(tree, proto_cups, tvb, offset, -1, ENC_NA);
cups_tree = proto_item_add_subtree(ti, ett_cups);
/* Format (1450 bytes max.): */
/* type state uri ["location" ["info" ["make-and-model"]]]\n */
ptype = get_hex_uint(tvb, offset, &next_offset);
len = next_offset - offset;
if (len != 0) {
ti = proto_tree_add_uint(cups_tree, hf_cups_ptype, tvb, offset, len, ptype);
ptype_subtree = proto_item_add_subtree(ti, ett_cups_ptype);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_default, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_implicit, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_variable, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_large, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_medium, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_small, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_sort, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_bind, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_cover, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_punch, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_collate, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_copies, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_staple, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_duplex, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_color, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_bw, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_remote, tvb, offset, len, ENC_BIG_ENDIAN);
proto_tree_add_item(ptype_subtree, hf_cups_ptype_class, tvb, offset, len, ENC_BIG_ENDIAN);
}
offset = next_offset;
if (!skip_space(tvb, offset, &next_offset))
return offset; /* end of packet */
offset = next_offset;
state = get_hex_uint(tvb, offset, &next_offset);
len = next_offset - offset;
if (len != 0) {
proto_tree_add_uint(cups_tree, hf_cups_state, tvb, offset, len, state);
}
offset = next_offset;
if (!skip_space(tvb, offset, &next_offset))
return offset; /* end of packet */
offset = next_offset;
str = get_unquoted_string(tvb, offset, &next_offset, &len);
if (str == NULL)
return offset; /* separator/terminator not found */
proto_tree_add_string(cups_tree, hf_cups_uri, tvb, offset, len, str);
col_add_fstr(pinfo->cinfo, COL_INFO, "%.*s (%s)",
(guint16) len, str, val_to_str(state, cups_state_values, "0x%x"));
offset = next_offset;
if (!cups_tree)
return offset;
if (!skip_space(tvb, offset, &next_offset))
return offset; /* end of packet */
offset = next_offset;
str = get_quoted_string(tvb, offset, &next_offset, &len);
if (str == NULL)
return offset; /* separator/terminator not found */
proto_tree_add_string(cups_tree, hf_cups_location, tvb, offset+1, len, str);
offset = next_offset;
if (!skip_space(tvb, offset, &next_offset))
return offset; /* end of packet */
offset = next_offset;
str = get_quoted_string(tvb, offset, &next_offset, &len);
if (str == NULL)
return offset; /* separator/terminator not found */
proto_tree_add_string(cups_tree, hf_cups_information, tvb, offset+1, len, str);
offset = next_offset;
if (!skip_space(tvb, offset, &next_offset))
return offset; /* end of packet */
offset = next_offset;
str = get_quoted_string(tvb, offset, &next_offset, &len);
if (str == NULL)
return offset; /* separator/terminator not found */
proto_tree_add_string(cups_tree, hf_cups_make_model, tvb, offset+1, len, str);
return next_offset;
}
static guint
get_hex_uint(tvbuff_t *tvb, gint offset, gint *next_offset)
{
int c;
guint u = 0;
while (g_ascii_isxdigit(c = tvb_get_guint8(tvb, offset))) {
u = 16*u + ws_xton(c);
offset++;
}
*next_offset = offset;
return u;
}
static gboolean
skip_space(tvbuff_t *tvb, gint offset, gint *next_offset)
{
int c;
while ((c = tvb_get_guint8(tvb, offset)) == ' ')
offset++;
if (c == '\r' || c == '\n')
return FALSE; /* end of packet */
*next_offset = offset;
return TRUE;
}
static const guint8*
get_quoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len)
{
int c;
const guint8* s = NULL;
guint l = 0;
gint o;
c = tvb_get_guint8(tvb, offset);
if (c == '"') {
o = tvb_find_guint8(tvb, offset+1, -1, '"');
if (o != -1) {
offset++;
l = o - offset;
s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, l, ENC_UTF_8);
offset = o + 1;
}
}
*next_offset = offset;
*len = l;
return s;
}
static const guint8*
get_unquoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len)
{
const guint8* s = NULL;
guint l = 0;
gint o;
o = tvb_ws_mempbrk_pattern_guint8(tvb, offset, -1, &pbrk_whitespace, NULL);
if (o != -1) {
l = o - offset;
s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, l, ENC_UTF_8);
offset = o;
}
*next_offset = offset;
*len = l;
return s;
}
/**********************************************************************/
void
proto_register_cups(void)
{
static hf_register_info hf[] = {
{ &hf_cups_ptype,
{ "Type", "cups.ptype", FT_UINT32, BASE_HEX,
NULL, 0x0, NULL, HFILL }},
{ &hf_cups_ptype_default,
{ "Default printer on network", "cups.ptype.default", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_DEFAULT, NULL, HFILL }},
{ &hf_cups_ptype_implicit,
{ "Class", "cups.ptype.implicit", FT_BOOLEAN, 32,
TFS(&tfs_implicit_explicit), CUPS_PRINTER_IMPLICIT, NULL, HFILL }},
{ &hf_cups_ptype_variable,
{ "Can print variable sizes", "cups.ptype.variable", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_VARIABLE, NULL, HFILL }},
{ &hf_cups_ptype_large,
{ "Can print up to 36x48 inches", "cups.ptype.large", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_LARGE, NULL, HFILL }},
{ &hf_cups_ptype_medium,
{ "Can print up to 18x24 inches", "cups.ptype.medium", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_MEDIUM, NULL, HFILL }},
{ &hf_cups_ptype_small,
{ "Can print up to 9x14 inches", "cups.ptype.small", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_SMALL, NULL, HFILL }},
{ &hf_cups_ptype_sort,
{ "Can sort", "cups.ptype.sort", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_SORT, NULL, HFILL }},
{ &hf_cups_ptype_bind,
{ "Can bind", "cups.ptype.bind", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_BIND, NULL, HFILL }},
{ &hf_cups_ptype_cover,
{ "Can cover", "cups.ptype.cover", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_COVER, NULL, HFILL }},
{ &hf_cups_ptype_punch,
{ "Can punch holes", "cups.ptype.punch", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_PUNCH, NULL, HFILL }},
{ &hf_cups_ptype_collate,
{ "Can do fast collating", "cups.ptype.collate", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_COLLATE, NULL, HFILL }},
{ &hf_cups_ptype_copies,
{ "Can do fast copies", "cups.ptype.copies", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_COPIES, NULL, HFILL }},
{ &hf_cups_ptype_staple,
{ "Can staple", "cups.ptype.staple", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_STAPLE, NULL, HFILL }},
{ &hf_cups_ptype_duplex,
{ "Can duplex", "cups.ptype.duplex", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_DUPLEX, NULL, HFILL }},
{ &hf_cups_ptype_color,
{ "Can print color", "cups.ptype.color", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_COLOR, NULL, HFILL }},
{ &hf_cups_ptype_bw,
{ "Can print black", "cups.ptype.bw", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_BW, NULL, HFILL }},
{ &hf_cups_ptype_remote,
{ "Remote", "cups.ptype.remote", FT_BOOLEAN, 32,
TFS(&tfs_yes_no), CUPS_PRINTER_REMOTE, NULL, HFILL }},
{ &hf_cups_ptype_class,
{ "Class", "cups.ptype.class", FT_BOOLEAN, 32,
TFS(&tfs_printer_class), CUPS_PRINTER_CLASS, NULL, HFILL }},
{ &hf_cups_state,
{ "State", "cups.state", FT_UINT8, BASE_HEX,
VALS(cups_state_values), 0x0, NULL, HFILL }},
{ &hf_cups_uri,
{ "URI", "cups.uri", FT_STRING, BASE_NONE,
NULL, 0x0, NULL, HFILL }},
{ &hf_cups_location,
{ "Location", "cups.location", FT_STRING, BASE_NONE,
NULL, 0x0, NULL, HFILL }},
{ &hf_cups_information,
{ "Information", "cups.information", FT_STRING, BASE_NONE,
NULL, 0x0, NULL, HFILL }},
{ &hf_cups_make_model,
{ "Make and model", "cups.make_model", FT_STRING, BASE_NONE,
NULL, 0x0, NULL, HFILL }},
};
static gint *ett[] = {
&ett_cups,
&ett_cups_ptype
};
proto_cups = proto_register_protocol("Common Unix Printing System (CUPS) Browsing Protocol", "CUPS", "cups");
proto_register_field_array(proto_cups, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
/* compile patterns */
ws_mempbrk_compile(&pbrk_whitespace, " \t\r\n");
}
void
proto_reg_handoff_cups(void)
{
dissector_handle_t cups_handle;
cups_handle = create_dissector_handle(dissect_cups, proto_cups);
dissector_add_uint_with_preference("udp.port", UDP_PORT_CUPS, cups_handle);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/