Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-cups.c
blob6d8541336e1074262af683d15ef05e7603cd6eb4
1 /* packet-cups.c
2 * Routines for Common Unix Printing System (CUPS) Browsing Protocol
3 * packet disassembly for the Wireshark network traffic analyzer.
5 * Charles Levert <charles@comm.polymtl.ca>
6 * Copyright 2001 Charles Levert
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <epan/packet.h>
15 #include <epan/tfs.h>
16 #include <wsutil/str_util.h>
18 /**********************************************************************/
20 void proto_register_cups(void);
21 void proto_reg_handoff_cups(void);
23 static dissector_handle_t cups_handle;
25 /* From cups/cups.h, GNU GPL, Copyright 1997-2001 by Easy Software Products. */
26 typedef uint32_t cups_ptype_t; /**** Printer Type/Capability Bits ****/
27 enum /* Not a typedef'd enum so we can OR */
29 CUPS_PRINTER_LOCAL = 0x0000, /* Local printer or class */
30 CUPS_PRINTER_CLASS = 0x0001, /* Printer class */
31 CUPS_PRINTER_REMOTE = 0x0002, /* Remote printer or class */
32 CUPS_PRINTER_BW = 0x0004, /* Can do B&W printing */
33 CUPS_PRINTER_COLOR = 0x0008, /* Can do color printing */
34 CUPS_PRINTER_DUPLEX = 0x0010, /* Can do duplexing */
35 CUPS_PRINTER_STAPLE = 0x0020, /* Can staple output */
36 CUPS_PRINTER_COPIES = 0x0040, /* Can do copies */
37 CUPS_PRINTER_COLLATE = 0x0080, /* Can collage copies */
38 CUPS_PRINTER_PUNCH = 0x0100, /* Can punch output */
39 CUPS_PRINTER_COVER = 0x0200, /* Can cover output */
40 CUPS_PRINTER_BIND = 0x0400, /* Can bind output */
41 CUPS_PRINTER_SORT = 0x0800, /* Can sort output */
42 CUPS_PRINTER_SMALL = 0x1000, /* Can do Letter/Legal/A4 */
43 CUPS_PRINTER_MEDIUM = 0x2000, /* Can do Tabloid/B/C/A3/A2 */
44 CUPS_PRINTER_LARGE = 0x4000, /* Can do D/E/A1/A0 */
45 CUPS_PRINTER_VARIABLE = 0x8000, /* Can do variable sizes */
46 CUPS_PRINTER_IMPLICIT = 0x10000, /* Implicit class */
47 CUPS_PRINTER_DEFAULT = 0x20000, /* Default printer on network */
48 CUPS_PRINTER_OPTIONS = 0xfffc /* ~(CLASS | REMOTE | IMPLICIT) */
50 /* End insert from cups/cups.h */
52 typedef enum _cups_state {
53 CUPS_IDLE = 3,
54 CUPS_PROCESSING,
55 CUPS_STOPPED
56 } cups_state_t;
58 static const value_string cups_state_values[] = {
59 { CUPS_IDLE, "idle" },
60 { CUPS_PROCESSING, "processing" },
61 { CUPS_STOPPED, "stopped" },
62 { 0, NULL }
65 static const true_false_string tfs_implicit_explicit = { "Implicit class", "Explicit class" };
66 static const true_false_string tfs_printer_class = { "Printer class", "Single printer" };
68 static int proto_cups;
69 static int hf_cups_ptype;
70 static int hf_cups_ptype_default;
71 static int hf_cups_ptype_implicit;
72 static int hf_cups_ptype_variable;
73 static int hf_cups_ptype_large;
74 static int hf_cups_ptype_medium;
75 static int hf_cups_ptype_small;
76 static int hf_cups_ptype_sort;
77 static int hf_cups_ptype_bind;
78 static int hf_cups_ptype_cover;
79 static int hf_cups_ptype_punch;
80 static int hf_cups_ptype_collate;
81 static int hf_cups_ptype_copies;
82 static int hf_cups_ptype_staple;
83 static int hf_cups_ptype_duplex;
84 static int hf_cups_ptype_color;
85 static int hf_cups_ptype_bw;
86 static int hf_cups_ptype_remote;
87 static int hf_cups_ptype_class;
88 static int hf_cups_state;
89 static int hf_cups_uri;
90 static int hf_cups_location;
91 static int hf_cups_information;
92 static int hf_cups_make_model;
94 static int ett_cups;
95 static int ett_cups_ptype;
97 /* patterns used for tvb_ws_mempbrk_pattern_uint8 */
98 static ws_mempbrk_pattern pbrk_whitespace;
100 /* This protocol is heavily related to IPP, but it is CUPS-specific
101 and non-standard. */
102 #define UDP_PORT_CUPS 631
103 #define PROTO_TAG_CUPS "CUPS"
105 static unsigned get_hex_uint(tvbuff_t *tvb, int offset, int *next_offset);
106 static bool skip_space(tvbuff_t *tvb, int offset, int *next_offset);
107 static const uint8_t* get_quoted_string(wmem_allocator_t *scope, tvbuff_t *tvb, int offset,
108 int *next_offset, unsigned *len);
109 static const uint8_t* get_unquoted_string(wmem_allocator_t *scope, tvbuff_t *tvb, int offset,
110 int *next_offset, unsigned *len);
112 /**********************************************************************/
114 static int
115 dissect_cups(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
117 proto_tree *cups_tree = NULL;
118 proto_tree *ptype_subtree = NULL;
119 proto_item *ti = NULL;
120 int offset = 0;
121 int next_offset;
122 unsigned len;
123 const uint8_t *str;
124 cups_ptype_t ptype;
125 unsigned int state;
127 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_CUPS);
128 col_clear(pinfo->cinfo, COL_INFO);
130 ti = proto_tree_add_item(tree, proto_cups, tvb, offset, -1, ENC_NA);
131 cups_tree = proto_item_add_subtree(ti, ett_cups);
133 /* Format (1450 bytes max.): */
134 /* type state uri ["location" ["info" ["make-and-model"]]]\n */
136 ptype = get_hex_uint(tvb, offset, &next_offset);
137 len = next_offset - offset;
138 if (len != 0) {
139 ti = proto_tree_add_uint(cups_tree, hf_cups_ptype, tvb, offset, len, ptype);
140 ptype_subtree = proto_item_add_subtree(ti, ett_cups_ptype);
141 proto_tree_add_item(ptype_subtree, hf_cups_ptype_default, tvb, offset, len, ENC_BIG_ENDIAN);
142 proto_tree_add_item(ptype_subtree, hf_cups_ptype_implicit, tvb, offset, len, ENC_BIG_ENDIAN);
143 proto_tree_add_item(ptype_subtree, hf_cups_ptype_variable, tvb, offset, len, ENC_BIG_ENDIAN);
144 proto_tree_add_item(ptype_subtree, hf_cups_ptype_large, tvb, offset, len, ENC_BIG_ENDIAN);
145 proto_tree_add_item(ptype_subtree, hf_cups_ptype_medium, tvb, offset, len, ENC_BIG_ENDIAN);
146 proto_tree_add_item(ptype_subtree, hf_cups_ptype_small, tvb, offset, len, ENC_BIG_ENDIAN);
147 proto_tree_add_item(ptype_subtree, hf_cups_ptype_sort, tvb, offset, len, ENC_BIG_ENDIAN);
148 proto_tree_add_item(ptype_subtree, hf_cups_ptype_bind, tvb, offset, len, ENC_BIG_ENDIAN);
149 proto_tree_add_item(ptype_subtree, hf_cups_ptype_cover, tvb, offset, len, ENC_BIG_ENDIAN);
150 proto_tree_add_item(ptype_subtree, hf_cups_ptype_punch, tvb, offset, len, ENC_BIG_ENDIAN);
151 proto_tree_add_item(ptype_subtree, hf_cups_ptype_collate, tvb, offset, len, ENC_BIG_ENDIAN);
152 proto_tree_add_item(ptype_subtree, hf_cups_ptype_copies, tvb, offset, len, ENC_BIG_ENDIAN);
153 proto_tree_add_item(ptype_subtree, hf_cups_ptype_staple, tvb, offset, len, ENC_BIG_ENDIAN);
154 proto_tree_add_item(ptype_subtree, hf_cups_ptype_duplex, tvb, offset, len, ENC_BIG_ENDIAN);
155 proto_tree_add_item(ptype_subtree, hf_cups_ptype_color, tvb, offset, len, ENC_BIG_ENDIAN);
156 proto_tree_add_item(ptype_subtree, hf_cups_ptype_bw, tvb, offset, len, ENC_BIG_ENDIAN);
157 proto_tree_add_item(ptype_subtree, hf_cups_ptype_remote, tvb, offset, len, ENC_BIG_ENDIAN);
158 proto_tree_add_item(ptype_subtree, hf_cups_ptype_class, tvb, offset, len, ENC_BIG_ENDIAN);
160 offset = next_offset;
162 if (!skip_space(tvb, offset, &next_offset))
163 return offset; /* end of packet */
164 offset = next_offset;
166 state = get_hex_uint(tvb, offset, &next_offset);
167 len = next_offset - offset;
168 if (len != 0) {
169 proto_tree_add_uint(cups_tree, hf_cups_state, tvb, offset, len, state);
171 offset = next_offset;
173 if (!skip_space(tvb, offset, &next_offset))
174 return offset; /* end of packet */
175 offset = next_offset;
177 str = get_unquoted_string(pinfo->pool, tvb, offset, &next_offset, &len);
178 if (str == NULL)
179 return offset; /* separator/terminator not found */
181 proto_tree_add_string(cups_tree, hf_cups_uri, tvb, offset, len, str);
182 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)",
183 str, val_to_str(state, cups_state_values, "0x%x"));
184 offset = next_offset;
186 if (!cups_tree)
187 return offset;
189 if (!skip_space(tvb, offset, &next_offset))
190 return offset; /* end of packet */
191 offset = next_offset;
193 str = get_quoted_string(pinfo->pool, tvb, offset, &next_offset, &len);
194 if (str == NULL)
195 return offset; /* separator/terminator not found */
196 proto_tree_add_string(cups_tree, hf_cups_location, tvb, offset+1, len, str);
197 offset = next_offset;
199 if (!skip_space(tvb, offset, &next_offset))
200 return offset; /* end of packet */
201 offset = next_offset;
203 str = get_quoted_string(pinfo->pool, tvb, offset, &next_offset, &len);
204 if (str == NULL)
205 return offset; /* separator/terminator not found */
206 proto_tree_add_string(cups_tree, hf_cups_information, tvb, offset+1, len, str);
207 offset = next_offset;
209 if (!skip_space(tvb, offset, &next_offset))
210 return offset; /* end of packet */
211 offset = next_offset;
213 str = get_quoted_string(pinfo->pool, tvb, offset, &next_offset, &len);
214 if (str == NULL)
215 return offset; /* separator/terminator not found */
216 proto_tree_add_string(cups_tree, hf_cups_make_model, tvb, offset+1, len, str);
218 return next_offset;
221 static unsigned
222 get_hex_uint(tvbuff_t *tvb, int offset, int *next_offset)
224 int c;
225 unsigned u = 0;
227 while (g_ascii_isxdigit(c = tvb_get_uint8(tvb, offset))) {
228 u = 16*u + ws_xton(c);
230 offset++;
233 *next_offset = offset;
235 return u;
238 static bool
239 skip_space(tvbuff_t *tvb, int offset, int *next_offset)
241 int c;
243 while ((c = tvb_get_uint8(tvb, offset)) == ' ')
244 offset++;
245 if (c == '\r' || c == '\n')
246 return false; /* end of packet */
248 *next_offset = offset;
250 return true;
253 static const uint8_t*
254 get_quoted_string(wmem_allocator_t *scope, tvbuff_t *tvb, int offset, int *next_offset, unsigned *len)
256 int c;
257 const uint8_t* s = NULL;
258 unsigned l = 0;
259 int o;
261 c = tvb_get_uint8(tvb, offset);
262 if (c == '"') {
263 o = tvb_find_uint8(tvb, offset+1, -1, '"');
264 if (o != -1) {
265 offset++;
266 l = o - offset;
267 s = tvb_get_string_enc(scope, tvb, offset, l, ENC_UTF_8);
268 offset = o + 1;
272 *next_offset = offset;
273 *len = l;
275 return s;
278 static const uint8_t*
279 get_unquoted_string(wmem_allocator_t *scope, tvbuff_t *tvb, int offset, int *next_offset, unsigned *len)
281 const uint8_t* s = NULL;
282 unsigned l = 0;
283 int o;
285 o = tvb_ws_mempbrk_pattern_uint8(tvb, offset, -1, &pbrk_whitespace, NULL);
286 if (o != -1) {
287 l = o - offset;
288 s = tvb_get_string_enc(scope, tvb, offset, l, ENC_UTF_8);
289 offset = o;
292 *next_offset = offset;
293 *len = l;
295 return s;
298 /**********************************************************************/
300 void
301 proto_register_cups(void)
303 static hf_register_info hf[] = {
304 { &hf_cups_ptype,
305 { "Type", "cups.ptype", FT_UINT32, BASE_HEX,
306 NULL, 0x0, NULL, HFILL }},
307 { &hf_cups_ptype_default,
308 { "Default printer on network", "cups.ptype.default", FT_BOOLEAN, 32,
309 TFS(&tfs_yes_no), CUPS_PRINTER_DEFAULT, NULL, HFILL }},
310 { &hf_cups_ptype_implicit,
311 { "Class", "cups.ptype.implicit", FT_BOOLEAN, 32,
312 TFS(&tfs_implicit_explicit), CUPS_PRINTER_IMPLICIT, NULL, HFILL }},
313 { &hf_cups_ptype_variable,
314 { "Can print variable sizes", "cups.ptype.variable", FT_BOOLEAN, 32,
315 TFS(&tfs_yes_no), CUPS_PRINTER_VARIABLE, NULL, HFILL }},
316 { &hf_cups_ptype_large,
317 { "Can print up to 36x48 inches", "cups.ptype.large", FT_BOOLEAN, 32,
318 TFS(&tfs_yes_no), CUPS_PRINTER_LARGE, NULL, HFILL }},
319 { &hf_cups_ptype_medium,
320 { "Can print up to 18x24 inches", "cups.ptype.medium", FT_BOOLEAN, 32,
321 TFS(&tfs_yes_no), CUPS_PRINTER_MEDIUM, NULL, HFILL }},
322 { &hf_cups_ptype_small,
323 { "Can print up to 9x14 inches", "cups.ptype.small", FT_BOOLEAN, 32,
324 TFS(&tfs_yes_no), CUPS_PRINTER_SMALL, NULL, HFILL }},
325 { &hf_cups_ptype_sort,
326 { "Can sort", "cups.ptype.sort", FT_BOOLEAN, 32,
327 TFS(&tfs_yes_no), CUPS_PRINTER_SORT, NULL, HFILL }},
328 { &hf_cups_ptype_bind,
329 { "Can bind", "cups.ptype.bind", FT_BOOLEAN, 32,
330 TFS(&tfs_yes_no), CUPS_PRINTER_BIND, NULL, HFILL }},
331 { &hf_cups_ptype_cover,
332 { "Can cover", "cups.ptype.cover", FT_BOOLEAN, 32,
333 TFS(&tfs_yes_no), CUPS_PRINTER_COVER, NULL, HFILL }},
334 { &hf_cups_ptype_punch,
335 { "Can punch holes", "cups.ptype.punch", FT_BOOLEAN, 32,
336 TFS(&tfs_yes_no), CUPS_PRINTER_PUNCH, NULL, HFILL }},
337 { &hf_cups_ptype_collate,
338 { "Can do fast collating", "cups.ptype.collate", FT_BOOLEAN, 32,
339 TFS(&tfs_yes_no), CUPS_PRINTER_COLLATE, NULL, HFILL }},
340 { &hf_cups_ptype_copies,
341 { "Can do fast copies", "cups.ptype.copies", FT_BOOLEAN, 32,
342 TFS(&tfs_yes_no), CUPS_PRINTER_COPIES, NULL, HFILL }},
343 { &hf_cups_ptype_staple,
344 { "Can staple", "cups.ptype.staple", FT_BOOLEAN, 32,
345 TFS(&tfs_yes_no), CUPS_PRINTER_STAPLE, NULL, HFILL }},
346 { &hf_cups_ptype_duplex,
347 { "Can duplex", "cups.ptype.duplex", FT_BOOLEAN, 32,
348 TFS(&tfs_yes_no), CUPS_PRINTER_DUPLEX, NULL, HFILL }},
349 { &hf_cups_ptype_color,
350 { "Can print color", "cups.ptype.color", FT_BOOLEAN, 32,
351 TFS(&tfs_yes_no), CUPS_PRINTER_COLOR, NULL, HFILL }},
352 { &hf_cups_ptype_bw,
353 { "Can print black", "cups.ptype.bw", FT_BOOLEAN, 32,
354 TFS(&tfs_yes_no), CUPS_PRINTER_BW, NULL, HFILL }},
355 { &hf_cups_ptype_remote,
356 { "Remote", "cups.ptype.remote", FT_BOOLEAN, 32,
357 TFS(&tfs_yes_no), CUPS_PRINTER_REMOTE, NULL, HFILL }},
358 { &hf_cups_ptype_class,
359 { "Class", "cups.ptype.class", FT_BOOLEAN, 32,
360 TFS(&tfs_printer_class), CUPS_PRINTER_CLASS, NULL, HFILL }},
361 { &hf_cups_state,
362 { "State", "cups.state", FT_UINT8, BASE_HEX,
363 VALS(cups_state_values), 0x0, NULL, HFILL }},
364 { &hf_cups_uri,
365 { "URI", "cups.uri", FT_STRING, BASE_NONE,
366 NULL, 0x0, NULL, HFILL }},
367 { &hf_cups_location,
368 { "Location", "cups.location", FT_STRING, BASE_NONE,
369 NULL, 0x0, NULL, HFILL }},
370 { &hf_cups_information,
371 { "Information", "cups.information", FT_STRING, BASE_NONE,
372 NULL, 0x0, NULL, HFILL }},
373 { &hf_cups_make_model,
374 { "Make and model", "cups.make_model", FT_STRING, BASE_NONE,
375 NULL, 0x0, NULL, HFILL }},
378 static int *ett[] = {
379 &ett_cups,
380 &ett_cups_ptype
383 proto_cups = proto_register_protocol("Common Unix Printing System (CUPS) Browsing Protocol", "CUPS", "cups");
384 cups_handle = register_dissector("cups", dissect_cups, proto_cups);
385 proto_register_field_array(proto_cups, hf, array_length(hf));
386 proto_register_subtree_array(ett, array_length(ett));
388 /* compile patterns */
389 ws_mempbrk_compile(&pbrk_whitespace, " \t\r\n");
392 void
393 proto_reg_handoff_cups(void)
395 dissector_add_uint_with_preference("udp.port", UDP_PORT_CUPS, cups_handle);
399 * Editor modelines - https://www.wireshark.org/tools/modelines.html
401 * Local variables:
402 * c-basic-offset: 4
403 * tab-width: 8
404 * indent-tabs-mode: nil
405 * End:
407 * vi: set shiftwidth=4 tabstop=8 expandtab:
408 * :indentSize=4:tabSize=8:noTabs=true: