Add in some heuristics to try to detect AIX libpcap format. (This works
[obnox/wireshark/wip.git] / packet-who.c
1 /* packet-who.c
2  * Routines for who protocol (see man rwhod)
3  * Gilbert Ramirez <gram@xiexie.org>
4  *
5  * $Id: packet-who.c,v 1.18 2001/09/14 07:10:06 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <string.h>
36 #include <time.h>
37 #include <glib.h>
38 #include "packet.h"
39
40
41 /*
42  *
43 RWHOD(8)                 UNIX System Manager's Manual                 RWHOD(8)
44
45
46      The messages sent and received, are of the form:
47
48            struct  outmp {
49 0                   char    out_line[8];             tty name 
50 8                   char    out_name[8];             user id 
51 16                   long    out_time;               time on 
52            };
53
54            struct  whod {
55  0                   char    wd_vers;
56  1                   char    wd_type;
57  2                   char    wd_fill[2];
58  4                   int     wd_sendtime;
59  8                   int     wd_recvtime;
60 12                   char    wd_hostname[32];
61 44                   int     wd_loadav[3];
62 56                   int     wd_boottime;
63 60                   struct  whoent {
64                            struct  outmp we_utmp;
65 (20 each)                  int     we_idle;
66                    } wd_we[1024 / sizeof (struct whoent)];
67            };
68
69  Linux 2.0                       May 13, 1997                                2
70
71  *
72  */
73
74 static int proto_who = -1;
75 static int hf_who_vers = -1;
76 static int hf_who_type = -1;
77 static int hf_who_sendtime = -1;
78 static int hf_who_recvtime = -1;
79 static int hf_who_hostname = -1;
80 static int hf_who_loadav_5 = -1;
81 static int hf_who_loadav_10 = -1;
82 static int hf_who_loadav_15 = -1;
83 static int hf_who_boottime = -1;
84 static int hf_who_whoent = -1;
85 static int hf_who_tty = -1;
86 static int hf_who_uid = -1;
87 static int hf_who_timeon = -1;
88 static int hf_who_idle = -1;
89
90 static gint ett_who = -1;
91 static gint ett_whoent = -1;
92
93 #define UDP_PORT_WHO    513
94
95 static void dissect_whoent(tvbuff_t *tvb, int offset, proto_tree *tree);
96
97 static void
98 dissect_who(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
99 {
100         int             offset = 0;
101         proto_tree      *who_tree = NULL;
102         proto_item      *who_ti = NULL;
103         gchar           server_name[33];
104         double          loadav_5 = 0.0, loadav_10 = 0.0, loadav_15 = 0.0;
105         nstime_t        ts;
106
107         /* Summary information */
108         if (check_col(pinfo->fd, COL_PROTOCOL))
109                 col_set_str(pinfo->fd, COL_PROTOCOL, "WHO");
110         if (check_col(pinfo->fd, COL_INFO))
111                 col_clear(pinfo->fd, COL_INFO);
112
113         ts.nsecs = 0;
114
115         if (tree) {
116                 who_ti = proto_tree_add_item(tree, proto_who, tvb, offset,
117                     tvb_length(tvb), FALSE);
118                 who_tree = proto_item_add_subtree(who_ti, ett_who);
119         }
120
121         if (tree)
122                 proto_tree_add_item(who_tree, hf_who_vers, tvb, offset, 1, FALSE);
123         offset += 1;
124
125         if (tree)
126                 proto_tree_add_item(who_tree, hf_who_type, tvb, offset, 1, FALSE);
127         offset += 1;
128
129         /* 2 filler bytes */
130         offset += 2;
131
132         if (tree) {
133                 ts.secs = tvb_get_ntohl(tvb, offset);
134                 proto_tree_add_time(who_tree, hf_who_sendtime, tvb, offset, 4,
135                     &ts);
136         }
137         offset += 4;
138
139         if (tree) {
140                 ts.secs = tvb_get_ntohl(tvb, offset);
141                 proto_tree_add_time(who_tree, hf_who_recvtime, tvb, offset, 4,
142                     &ts);
143         }
144         offset += 4;
145
146         tvb_get_nstringz0(tvb, offset, 32, server_name);
147         if (tree)
148                 proto_tree_add_string(who_tree, hf_who_hostname, tvb, offset,
149                     32, server_name);
150         offset += 32;
151
152         loadav_5  = (double) tvb_get_ntohl(tvb, offset) / 100.0;
153         if (tree)
154                 proto_tree_add_double(who_tree, hf_who_loadav_5, tvb, offset,
155                     4, loadav_5);
156         offset += 4;
157
158         loadav_10 = (double) tvb_get_ntohl(tvb, offset) / 100.0;
159         if (tree)
160                 proto_tree_add_double(who_tree, hf_who_loadav_10, tvb, offset,
161                     4, loadav_10);
162         offset += 4;
163
164         loadav_15 = (double) tvb_get_ntohl(tvb, offset) / 100.0;
165         if (tree)
166                 proto_tree_add_double(who_tree, hf_who_loadav_15, tvb, offset,
167                     4, loadav_15);
168         offset += 4;
169
170         /* Summary information */
171         if (check_col(pinfo->fd, COL_INFO))
172                 col_add_fstr(pinfo->fd, COL_INFO, "%s: %.02f %.02f %.02f",
173                                 server_name, loadav_5, loadav_10, loadav_15);
174
175         if (tree) {
176                 ts.secs = tvb_get_ntohl(tvb, offset);
177                 proto_tree_add_time(who_tree, hf_who_boottime, tvb, offset, 4,
178                     &ts);
179                 offset += 4;
180
181                 dissect_whoent(tvb, offset, who_tree);
182         }
183 }
184
185 /* The man page says that (1024 / sizeof(struct whoent)) is the maximum number
186  * of whoent structures in the packet. */
187 #define SIZE_OF_WHOENT  24
188 #define MAX_NUM_WHOENTS (1024 / SIZE_OF_WHOENT)
189
190 static void
191 dissect_whoent(tvbuff_t *tvb, int offset, proto_tree *tree)
192 {
193         proto_tree      *whoent_tree = NULL;
194         proto_item      *whoent_ti = NULL;
195         int             line_offset = offset;
196         gchar           out_line[9];    
197         gchar           out_name[9];    
198         nstime_t        ts;
199         int             whoent_num = 0;
200         guint32         idle_secs; /* say that out loud... */
201
202         ts.nsecs = 0;
203
204         while (tvb_reported_length_remaining(tvb, line_offset) > 0
205             && whoent_num < MAX_NUM_WHOENTS) {
206                 whoent_ti = proto_tree_add_item(tree, hf_who_whoent, tvb,
207                     line_offset, SIZE_OF_WHOENT, FALSE);
208                 whoent_tree = proto_item_add_subtree(whoent_ti, ett_whoent);
209
210                 tvb_get_nstringz0(tvb, line_offset, 8, out_line);
211                 proto_tree_add_string(whoent_tree, hf_who_tty, tvb, line_offset,
212                     8, out_line);
213                 line_offset += 8;
214
215                 tvb_get_nstringz0(tvb, line_offset, 8, out_name);
216                 proto_tree_add_string(whoent_tree, hf_who_uid, tvb, line_offset,
217                     8, out_name);
218                 line_offset += 8;
219
220                 ts.secs = tvb_get_ntohl(tvb, line_offset);
221                 proto_tree_add_time(whoent_tree, hf_who_timeon, tvb,
222                     line_offset, 4, &ts);
223                 line_offset += 4;
224
225                 idle_secs = tvb_get_ntohl(tvb, line_offset);
226                 proto_tree_add_uint_format(whoent_tree, hf_who_idle, tvb,
227                     line_offset, 4, idle_secs, "Idle: %s",
228                     time_secs_to_str(idle_secs));
229                 line_offset += 4;
230
231                 whoent_num++;
232         }
233 }
234
235 void
236 proto_register_who(void)
237 {
238         static hf_register_info hf[] = {
239                 { &hf_who_vers,
240                 { "Version",    "who.vers", FT_UINT8, BASE_DEC, NULL, 0x0,
241                         "", HFILL }},
242
243                 { &hf_who_type,
244                 { "Type",       "who.type", FT_UINT8, BASE_DEC, NULL, 0x0,
245                         "", HFILL }},
246
247                 { &hf_who_sendtime,
248                 { "Send Time",  "who.sendtime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
249                         "", HFILL }},
250
251                 { &hf_who_recvtime,
252                 { "Receive Time", "who.recvtime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
253                         "", HFILL }},
254
255                 { &hf_who_hostname,
256                 { "Hostname", "who.hostname", FT_STRING, BASE_NONE, NULL, 0x0,
257                         "", HFILL }},
258
259                 { &hf_who_loadav_5,
260                 { "Load Average Over Past  5 Minutes", "who.loadav_5", FT_DOUBLE, BASE_NONE, NULL, 0x0,
261                         "", HFILL }},
262
263                 { &hf_who_loadav_10,
264                 { "Load Average Over Past 10 Minutes", "who.loadav_10", FT_DOUBLE, BASE_NONE, NULL, 0x0,
265                         "", HFILL }},
266
267                 { &hf_who_loadav_15,
268                 { "Load Average Over Past 15 Minutes", "who.loadav_15", FT_DOUBLE, BASE_NONE, NULL, 0x0,
269                         "", HFILL }},
270
271                 { &hf_who_boottime,
272                 { "Boot Time", "who.boottime", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
273                         "", HFILL }},
274
275                 { &hf_who_whoent,
276                 { "Who utmp Entry", "who.whoent", FT_NONE, BASE_NONE, NULL, 0x0,
277                         "", HFILL }},
278
279                 { &hf_who_tty,
280                 { "TTY Name", "who.tty", FT_STRING, BASE_NONE, NULL, 0x0,
281                         "", HFILL }},
282
283                 { &hf_who_uid,
284                 { "User ID", "who.uid", FT_STRING, BASE_NONE, NULL, 0x0,
285                         "", HFILL }},
286
287                 { &hf_who_timeon,
288                 { "Time On", "who.timeon", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
289                         "", HFILL }},
290
291                 { &hf_who_idle,
292                 { "Time Idle", "who.idle", FT_UINT32, BASE_DEC, NULL, 0x0,
293                         "", HFILL }},
294         };
295
296         static gint *ett[] = {
297                 &ett_who,
298                 &ett_whoent,
299         };
300
301         proto_who = proto_register_protocol("Who", "WHO", "who");
302         proto_register_field_array(proto_who, hf, array_length(hf));
303         proto_register_subtree_array(ett, array_length(ett));
304 }
305
306 void
307 proto_reg_handoff_who(void)
308 {
309         dissector_add("udp.port", UDP_PORT_WHO, dissect_who, proto_who);
310 }