wireshark/epan/dissectors/packet-cups.c
Michael Mann 2eb7b05b8c Convert most UDP dissectors to use "auto" preferences.
Similar to the "tcp.port" changes in I99604f95d426ad345f4b494598d94178b886eb67,
convert dissectors that use "udp.port".

More cleanup done on dissectors that use both TCP and UDP dissector
tables, so that less preference callbacks exist.

Change-Id: If07be9b9e850c244336a7069599cd554ce312dd3
Reviewed-on: https://code.wireshark.org/review/18120
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
2016-10-13 02:51:18 +00:00

421 lines
16 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
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#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_ASCII);
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_ASCII);
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 - http://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:
*/