print-radius.c revision 1.7
1/*
2 * Copyright (C) 2000 Alfredo Andres Omella.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 *   1. Redistributions of source code must retain the above copyright
9 *      notice, this list of conditions and the following disclaimer.
10 *   2. Redistributions in binary form must reproduce the above copyright
11 *      notice, this list of conditions and the following disclaimer in
12 *      the documentation and/or other materials provided with the
13 *      distribution.
14 *   3. The names of the authors may not be used to endorse or promote
15 *      products derived from this software without specific prior
16 *      written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 */
22/*
23 * Radius printer routines as specified on:
24 *
25 * RFC 2865:
26 *      "Remote Authentication Dial In User Service (RADIUS)"
27 *
28 * RFC 2866:
29 *      "RADIUS Accounting"
30 *
31 * RFC 2867:
32 *      "RADIUS Accounting Modifications for Tunnel Protocol Support"
33 *
34 * RFC 2868:
35 *      "RADIUS Attributes for Tunnel Protocol Support"
36 *
37 * RFC 2869:
38 *      "RADIUS Extensions"
39 *
40 * RFC 3580:
41 *      "IEEE 802.1X Remote Authentication Dial In User Service (RADIUS)"
42 *      "Usage Guidelines"
43 *
44 * RFC 4675:
45 *      "RADIUS Attributes for Virtual LAN and Priority Support"
46 *
47 * RFC 5176:
48 *      "Dynamic Authorization Extensions to RADIUS"
49 *
50 * Alfredo Andres Omella (aandres@s21sec.com) v0.1 2000/09/15
51 *
52 * TODO: Among other things to print ok MacIntosh and Vendor values
53 */
54
55#include <sys/cdefs.h>
56#ifndef lint
57__RCSID("$NetBSD: print-radius.c,v 1.7 2017/01/24 23:29:14 christos Exp $");
58#endif
59
60#ifdef HAVE_CONFIG_H
61#include "config.h"
62#endif
63
64#include <netdissect-stdinc.h>
65
66#include <string.h>
67
68#include "netdissect.h"
69#include "addrtoname.h"
70#include "extract.h"
71#include "oui.h"
72
73static const char tstr[] = " [|radius]";
74
75#define TAM_SIZE(x) (sizeof(x)/sizeof(x[0]) )
76
77#define PRINT_HEX(bytes_len, ptr_data)                               \
78           while(bytes_len)                                          \
79           {                                                         \
80              ND_PRINT((ndo, "%02X", *ptr_data ));                   \
81              ptr_data++;                                            \
82              bytes_len--;                                           \
83           }
84
85
86/* Radius packet codes */
87#define RADCMD_ACCESS_REQ   1 /* Access-Request      */
88#define RADCMD_ACCESS_ACC   2 /* Access-Accept       */
89#define RADCMD_ACCESS_REJ   3 /* Access-Reject       */
90#define RADCMD_ACCOUN_REQ   4 /* Accounting-Request  */
91#define RADCMD_ACCOUN_RES   5 /* Accounting-Response */
92#define RADCMD_ACCESS_CHA  11 /* Access-Challenge    */
93#define RADCMD_STATUS_SER  12 /* Status-Server       */
94#define RADCMD_STATUS_CLI  13 /* Status-Client       */
95#define RADCMD_DISCON_REQ  40 /* Disconnect-Request  */
96#define RADCMD_DISCON_ACK  41 /* Disconnect-ACK      */
97#define RADCMD_DISCON_NAK  42 /* Disconnect-NAK      */
98#define RADCMD_COA_REQ     43 /* CoA-Request         */
99#define RADCMD_COA_ACK     44 /* CoA-ACK             */
100#define RADCMD_COA_NAK     45 /* CoA-NAK             */
101#define RADCMD_RESERVED   255 /* Reserved            */
102
103static const struct tok radius_command_values[] = {
104    { RADCMD_ACCESS_REQ, "Access-Request" },
105    { RADCMD_ACCESS_ACC, "Access-Accept" },
106    { RADCMD_ACCESS_REJ, "Access-Reject" },
107    { RADCMD_ACCOUN_REQ, "Accounting-Request" },
108    { RADCMD_ACCOUN_RES, "Accounting-Response" },
109    { RADCMD_ACCESS_CHA, "Access-Challenge" },
110    { RADCMD_STATUS_SER, "Status-Server" },
111    { RADCMD_STATUS_CLI, "Status-Client" },
112    { RADCMD_DISCON_REQ, "Disconnect-Request" },
113    { RADCMD_DISCON_ACK, "Disconnect-ACK" },
114    { RADCMD_DISCON_NAK, "Disconnect-NAK" },
115    { RADCMD_COA_REQ,    "CoA-Request" },
116    { RADCMD_COA_ACK,    "CoA-ACK" },
117    { RADCMD_COA_NAK,    "CoA-NAK" },
118    { RADCMD_RESERVED,   "Reserved" },
119    { 0, NULL}
120};
121
122/********************************/
123/* Begin Radius Attribute types */
124/********************************/
125#define SERV_TYPE    6
126#define FRM_IPADDR   8
127#define LOG_IPHOST  14
128#define LOG_SERVICE 15
129#define FRM_IPX     23
130#define SESSION_TIMEOUT   27
131#define IDLE_TIMEOUT      28
132#define FRM_ATALK_LINK    37
133#define FRM_ATALK_NETWORK 38
134
135#define ACCT_DELAY        41
136#define ACCT_SESSION_TIME 46
137
138#define EGRESS_VLAN_ID   56
139#define EGRESS_VLAN_NAME 58
140
141#define TUNNEL_TYPE        64
142#define TUNNEL_MEDIUM      65
143#define TUNNEL_CLIENT_END  66
144#define TUNNEL_SERVER_END  67
145#define TUNNEL_PASS        69
146
147#define ARAP_PASS          70
148#define ARAP_FEATURES      71
149
150#define TUNNEL_PRIV_GROUP  81
151#define TUNNEL_ASSIGN_ID   82
152#define TUNNEL_PREFERENCE  83
153
154#define ARAP_CHALLENGE_RESP 84
155#define ACCT_INT_INTERVAL   85
156
157#define TUNNEL_CLIENT_AUTH 90
158#define TUNNEL_SERVER_AUTH 91
159/********************************/
160/* End Radius Attribute types */
161/********************************/
162
163#define RFC4675_TAGGED   0x31
164#define RFC4675_UNTAGGED 0x32
165
166static const struct tok rfc4675_tagged[] = {
167    { RFC4675_TAGGED,   "Tagged" },
168    { RFC4675_UNTAGGED, "Untagged" },
169    { 0, NULL}
170};
171
172
173static void print_attr_string(netdissect_options *, register const u_char *, u_int, u_short );
174static void print_attr_num(netdissect_options *, register const u_char *, u_int, u_short );
175static void print_vendor_attr(netdissect_options *, register const u_char *, u_int, u_short );
176static void print_attr_address(netdissect_options *, register const u_char *, u_int, u_short);
177static void print_attr_time(netdissect_options *, register const u_char *, u_int, u_short);
178static void print_attr_strange(netdissect_options *, register const u_char *, u_int, u_short);
179
180
181struct radius_hdr { uint8_t  code; /* Radius packet code  */
182                    uint8_t  id;   /* Radius packet id    */
183                    uint16_t len;  /* Radius total length */
184                    uint8_t  auth[16]; /* Authenticator   */
185                  };
186
187#define MIN_RADIUS_LEN	20
188
189struct radius_attr { uint8_t type; /* Attribute type   */
190                     uint8_t len;  /* Attribute length */
191                   };
192
193
194/* Service-Type Attribute standard values */
195static const char *serv_type[]={ NULL,
196                                "Login",
197                                "Framed",
198                                "Callback Login",
199                                "Callback Framed",
200                                "Outbound",
201                                "Administrative",
202                                "NAS Prompt",
203                                "Authenticate Only",
204                                "Callback NAS Prompt",
205                                "Call Check",
206                                "Callback Administrative",
207                               };
208
209/* Framed-Protocol Attribute standard values */
210static const char *frm_proto[]={ NULL,
211                                 "PPP",
212                                 "SLIP",
213                                 "ARAP",
214                                 "Gandalf proprietary",
215                                 "Xylogics IPX/SLIP",
216                                 "X.75 Synchronous",
217                               };
218
219/* Framed-Routing Attribute standard values */
220static const char *frm_routing[]={ "None",
221                                   "Send",
222                                   "Listen",
223                                   "Send&Listen",
224                                 };
225
226/* Framed-Compression Attribute standard values */
227static const char *frm_comp[]={ "None",
228                                "VJ TCP/IP",
229                                "IPX",
230                                "Stac-LZS",
231                              };
232
233/* Login-Service Attribute standard values */
234static const char *login_serv[]={ "Telnet",
235                                  "Rlogin",
236                                  "TCP Clear",
237                                  "PortMaster(proprietary)",
238                                  "LAT",
239                                  "X.25-PAD",
240                                  "X.25-T3POS",
241                                  "Unassigned",
242                                  "TCP Clear Quiet",
243                                };
244
245
246/* Termination-Action Attribute standard values */
247static const char *term_action[]={ "Default",
248                                   "RADIUS-Request",
249                                 };
250
251/* Ingress-Filters Attribute standard values */
252static const char *ingress_filters[]={ NULL,
253                                       "Enabled",
254                                       "Disabled",
255                                     };
256
257/* NAS-Port-Type Attribute standard values */
258static const char *nas_port_type[]={ "Async",
259                                     "Sync",
260                                     "ISDN Sync",
261                                     "ISDN Async V.120",
262                                     "ISDN Async V.110",
263                                     "Virtual",
264                                     "PIAFS",
265                                     "HDLC Clear Channel",
266                                     "X.25",
267                                     "X.75",
268                                     "G.3 Fax",
269                                     "SDSL",
270                                     "ADSL-CAP",
271                                     "ADSL-DMT",
272                                     "ISDN-DSL",
273                                     "Ethernet",
274                                     "xDSL",
275                                     "Cable",
276                                     "Wireless - Other",
277                                     "Wireless - IEEE 802.11",
278                                   };
279
280/* Acct-Status-Type Accounting Attribute standard values */
281static const char *acct_status[]={ NULL,
282                                   "Start",
283                                   "Stop",
284                                   "Interim-Update",
285                                   "Unassigned",
286                                   "Unassigned",
287                                   "Unassigned",
288                                   "Accounting-On",
289                                   "Accounting-Off",
290                                   "Tunnel-Start",
291                                   "Tunnel-Stop",
292                                   "Tunnel-Reject",
293                                   "Tunnel-Link-Start",
294                                   "Tunnel-Link-Stop",
295                                   "Tunnel-Link-Reject",
296                                   "Failed",
297                                 };
298
299/* Acct-Authentic Accounting Attribute standard values */
300static const char *acct_auth[]={ NULL,
301                                 "RADIUS",
302                                 "Local",
303                                 "Remote",
304                               };
305
306/* Acct-Terminate-Cause Accounting Attribute standard values */
307static const char *acct_term[]={ NULL,
308                                 "User Request",
309                                 "Lost Carrier",
310                                 "Lost Service",
311                                 "Idle Timeout",
312                                 "Session Timeout",
313                                 "Admin Reset",
314                                 "Admin Reboot",
315                                 "Port Error",
316                                 "NAS Error",
317                                 "NAS Request",
318                                 "NAS Reboot",
319                                 "Port Unneeded",
320                                 "Port Preempted",
321                                 "Port Suspended",
322                                 "Service Unavailable",
323                                 "Callback",
324                                 "User Error",
325                                 "Host Request",
326                               };
327
328/* Tunnel-Type Attribute standard values */
329static const char *tunnel_type[]={ NULL,
330                                   "PPTP",
331                                   "L2F",
332                                   "L2TP",
333                                   "ATMP",
334                                   "VTP",
335                                   "AH",
336                                   "IP-IP",
337                                   "MIN-IP-IP",
338                                   "ESP",
339                                   "GRE",
340                                   "DVS",
341                                   "IP-in-IP Tunneling",
342                                   "VLAN",
343                                 };
344
345/* Tunnel-Medium-Type Attribute standard values */
346static const char *tunnel_medium[]={ NULL,
347                                     "IPv4",
348                                     "IPv6",
349                                     "NSAP",
350                                     "HDLC",
351                                     "BBN 1822",
352                                     "802",
353                                     "E.163",
354                                     "E.164",
355                                     "F.69",
356                                     "X.121",
357                                     "IPX",
358                                     "Appletalk",
359                                     "Decnet IV",
360                                     "Banyan Vines",
361                                     "E.164 with NSAP subaddress",
362                                   };
363
364/* ARAP-Zone-Access Attribute standard values */
365static const char *arap_zone[]={ NULL,
366                                 "Only access to dfl zone",
367                                 "Use zone filter inc.",
368                                 "Not used",
369                                 "Use zone filter exc.",
370                               };
371
372static const char *prompt[]={ "No Echo",
373                              "Echo",
374                            };
375
376
377struct attrtype { const char *name;      /* Attribute name                 */
378                  const char **subtypes; /* Standard Values (if any)       */
379                  u_char siz_subtypes;   /* Size of total standard values  */
380                  u_char first_subtype;  /* First standard value is 0 or 1 */
381                  void (*print_func)(netdissect_options *, register const u_char *, u_int, u_short);
382                } attr_type[]=
383  {
384     { NULL,                              NULL, 0, 0, NULL               },
385     { "User-Name",                       NULL, 0, 0, print_attr_string  },
386     { "User-Password",                   NULL, 0, 0, NULL               },
387     { "CHAP-Password",                   NULL, 0, 0, NULL               },
388     { "NAS-IP-Address",                  NULL, 0, 0, print_attr_address },
389     { "NAS-Port",                        NULL, 0, 0, print_attr_num     },
390     { "Service-Type",                    serv_type, TAM_SIZE(serv_type)-1, 1, print_attr_num },
391     { "Framed-Protocol",                 frm_proto, TAM_SIZE(frm_proto)-1, 1, print_attr_num },
392     { "Framed-IP-Address",               NULL, 0, 0, print_attr_address },
393     { "Framed-IP-Netmask",               NULL, 0, 0, print_attr_address },
394     { "Framed-Routing",                  frm_routing, TAM_SIZE(frm_routing), 0, print_attr_num },
395     { "Filter-Id",                       NULL, 0, 0, print_attr_string  },
396     { "Framed-MTU",                      NULL, 0, 0, print_attr_num     },
397     { "Framed-Compression",              frm_comp, TAM_SIZE(frm_comp),   0, print_attr_num },
398     { "Login-IP-Host",                   NULL, 0, 0, print_attr_address },
399     { "Login-Service",                   login_serv, TAM_SIZE(login_serv), 0, print_attr_num },
400     { "Login-TCP-Port",                  NULL, 0, 0, print_attr_num     },
401     { "Unassigned",                      NULL, 0, 0, NULL }, /*17*/
402     { "Reply-Message",                   NULL, 0, 0, print_attr_string },
403     { "Callback-Number",                 NULL, 0, 0, print_attr_string },
404     { "Callback-Id",                     NULL, 0, 0, print_attr_string },
405     { "Unassigned",                      NULL, 0, 0, NULL }, /*21*/
406     { "Framed-Route",                    NULL, 0, 0, print_attr_string },
407     { "Framed-IPX-Network",              NULL, 0, 0, print_attr_num    },
408     { "State",                           NULL, 0, 0, print_attr_string },
409     { "Class",                           NULL, 0, 0, print_attr_string },
410     { "Vendor-Specific",                 NULL, 0, 0, print_vendor_attr },
411     { "Session-Timeout",                 NULL, 0, 0, print_attr_num    },
412     { "Idle-Timeout",                    NULL, 0, 0, print_attr_num    },
413     { "Termination-Action",              term_action, TAM_SIZE(term_action), 0, print_attr_num },
414     { "Called-Station-Id",               NULL, 0, 0, print_attr_string },
415     { "Calling-Station-Id",              NULL, 0, 0, print_attr_string },
416     { "NAS-Identifier",                  NULL, 0, 0, print_attr_string },
417     { "Proxy-State",                     NULL, 0, 0, print_attr_string },
418     { "Login-LAT-Service",               NULL, 0, 0, print_attr_string },
419     { "Login-LAT-Node",                  NULL, 0, 0, print_attr_string },
420     { "Login-LAT-Group",                 NULL, 0, 0, print_attr_string },
421     { "Framed-AppleTalk-Link",           NULL, 0, 0, print_attr_num    },
422     { "Framed-AppleTalk-Network",        NULL, 0, 0, print_attr_num    },
423     { "Framed-AppleTalk-Zone",           NULL, 0, 0, print_attr_string },
424     { "Acct-Status-Type",                acct_status, TAM_SIZE(acct_status)-1, 1, print_attr_num },
425     { "Acct-Delay-Time",                 NULL, 0, 0, print_attr_num    },
426     { "Acct-Input-Octets",               NULL, 0, 0, print_attr_num    },
427     { "Acct-Output-Octets",              NULL, 0, 0, print_attr_num    },
428     { "Acct-Session-Id",                 NULL, 0, 0, print_attr_string },
429     { "Acct-Authentic",                  acct_auth, TAM_SIZE(acct_auth)-1, 1, print_attr_num },
430     { "Acct-Session-Time",               NULL, 0, 0, print_attr_num },
431     { "Acct-Input-Packets",              NULL, 0, 0, print_attr_num },
432     { "Acct-Output-Packets",             NULL, 0, 0, print_attr_num },
433     { "Acct-Terminate-Cause",            acct_term, TAM_SIZE(acct_term)-1, 1, print_attr_num },
434     { "Acct-Multi-Session-Id",           NULL, 0, 0, print_attr_string },
435     { "Acct-Link-Count",                 NULL, 0, 0, print_attr_num },
436     { "Acct-Input-Gigawords",            NULL, 0, 0, print_attr_num },
437     { "Acct-Output-Gigawords",           NULL, 0, 0, print_attr_num },
438     { "Unassigned",                      NULL, 0, 0, NULL }, /*54*/
439     { "Event-Timestamp",                 NULL, 0, 0, print_attr_time },
440     { "Egress-VLANID",                   NULL, 0, 0, print_attr_num },
441     { "Ingress-Filters",                 ingress_filters, TAM_SIZE(ingress_filters)-1, 1, print_attr_num },
442     { "Egress-VLAN-Name",                NULL, 0, 0, print_attr_string },
443     { "User-Priority-Table",             NULL, 0, 0, NULL },
444     { "CHAP-Challenge",                  NULL, 0, 0, print_attr_string },
445     { "NAS-Port-Type",                   nas_port_type, TAM_SIZE(nas_port_type), 0, print_attr_num },
446     { "Port-Limit",                      NULL, 0, 0, print_attr_num },
447     { "Login-LAT-Port",                  NULL, 0, 0, print_attr_string }, /*63*/
448     { "Tunnel-Type",                     tunnel_type, TAM_SIZE(tunnel_type)-1, 1, print_attr_num },
449     { "Tunnel-Medium-Type",              tunnel_medium, TAM_SIZE(tunnel_medium)-1, 1, print_attr_num },
450     { "Tunnel-Client-Endpoint",          NULL, 0, 0, print_attr_string },
451     { "Tunnel-Server-Endpoint",          NULL, 0, 0, print_attr_string },
452     { "Acct-Tunnel-Connection",          NULL, 0, 0, print_attr_string },
453     { "Tunnel-Password",                 NULL, 0, 0, print_attr_string  },
454     { "ARAP-Password",                   NULL, 0, 0, print_attr_strange },
455     { "ARAP-Features",                   NULL, 0, 0, print_attr_strange },
456     { "ARAP-Zone-Access",                arap_zone, TAM_SIZE(arap_zone)-1, 1, print_attr_num }, /*72*/
457     { "ARAP-Security",                   NULL, 0, 0, print_attr_string },
458     { "ARAP-Security-Data",              NULL, 0, 0, print_attr_string },
459     { "Password-Retry",                  NULL, 0, 0, print_attr_num    },
460     { "Prompt",                          prompt, TAM_SIZE(prompt), 0, print_attr_num },
461     { "Connect-Info",                    NULL, 0, 0, print_attr_string   },
462     { "Configuration-Token",             NULL, 0, 0, print_attr_string   },
463     { "EAP-Message",                     NULL, 0, 0, print_attr_string   },
464     { "Message-Authenticator",           NULL, 0, 0, print_attr_string }, /*80*/
465     { "Tunnel-Private-Group-ID",         NULL, 0, 0, print_attr_string },
466     { "Tunnel-Assignment-ID",            NULL, 0, 0, print_attr_string },
467     { "Tunnel-Preference",               NULL, 0, 0, print_attr_num    },
468     { "ARAP-Challenge-Response",         NULL, 0, 0, print_attr_strange },
469     { "Acct-Interim-Interval",           NULL, 0, 0, print_attr_num     },
470     { "Acct-Tunnel-Packets-Lost",        NULL, 0, 0, print_attr_num }, /*86*/
471     { "NAS-Port-Id",                     NULL, 0, 0, print_attr_string },
472     { "Framed-Pool",                     NULL, 0, 0, print_attr_string },
473     { "CUI",                             NULL, 0, 0, print_attr_string },
474     { "Tunnel-Client-Auth-ID",           NULL, 0, 0, print_attr_string },
475     { "Tunnel-Server-Auth-ID",           NULL, 0, 0, print_attr_string },
476     { "Unassigned",                      NULL, 0, 0, NULL }, /*92*/
477     { "Unassigned",                      NULL, 0, 0, NULL }  /*93*/
478  };
479
480
481/*****************************/
482/* Print an attribute string */
483/* value pointed by 'data'   */
484/* and 'length' size.        */
485/*****************************/
486/* Returns nothing.          */
487/*****************************/
488static void
489print_attr_string(netdissect_options *ndo,
490                  register const u_char *data, u_int length, u_short attr_code)
491{
492   register u_int i;
493
494   ND_TCHECK2(data[0],length);
495
496   switch(attr_code)
497   {
498      case TUNNEL_PASS:
499           if (length < 3)
500           {
501              ND_PRINT((ndo, "%s", tstr));
502              return;
503           }
504           if (*data && (*data <=0x1F) )
505              ND_PRINT((ndo, "Tag[%u] ", *data));
506           else
507              ND_PRINT((ndo, "Tag[Unused] "));
508           data++;
509           length--;
510           ND_PRINT((ndo, "Salt %u ", EXTRACT_16BITS(data)));
511           data+=2;
512           length-=2;
513        break;
514      case TUNNEL_CLIENT_END:
515      case TUNNEL_SERVER_END:
516      case TUNNEL_PRIV_GROUP:
517      case TUNNEL_ASSIGN_ID:
518      case TUNNEL_CLIENT_AUTH:
519      case TUNNEL_SERVER_AUTH:
520           if (*data <= 0x1F)
521           {
522              if (length < 1)
523              {
524                 ND_PRINT((ndo, "%s", tstr));
525                 return;
526              }
527              if (*data)
528                ND_PRINT((ndo, "Tag[%u] ", *data));
529              else
530                ND_PRINT((ndo, "Tag[Unused] "));
531              data++;
532              length--;
533           }
534        break;
535      case EGRESS_VLAN_NAME:
536           ND_PRINT((ndo, "%s (0x%02x) ",
537                  tok2str(rfc4675_tagged,"Unknown tag",*data),
538                  *data));
539           data++;
540           length--;
541        break;
542   }
543
544   for (i=0; *data && i < length ; i++, data++)
545       ND_PRINT((ndo, "%c", (*data < 32 || *data > 126) ? '.' : *data));
546
547   return;
548
549   trunc:
550      ND_PRINT((ndo, "%s", tstr));
551}
552
553/*
554 * print vendor specific attributes
555 */
556static void
557print_vendor_attr(netdissect_options *ndo,
558                  register const u_char *data, u_int length, u_short attr_code _U_)
559{
560    u_int idx;
561    u_int vendor_id;
562    u_int vendor_type;
563    u_int vendor_length;
564
565    if (length < 4)
566        goto trunc;
567    ND_TCHECK2(*data, 4);
568    vendor_id = EXTRACT_32BITS(data);
569    data+=4;
570    length-=4;
571
572    ND_PRINT((ndo, "Vendor: %s (%u)",
573           tok2str(smi_values,"Unknown",vendor_id),
574           vendor_id));
575
576    while (length >= 2) {
577	ND_TCHECK2(*data, 2);
578
579        vendor_type = *(data);
580        vendor_length = *(data+1);
581
582        if (vendor_length < 2)
583        {
584            ND_PRINT((ndo, "\n\t    Vendor Attribute: %u, Length: %u (bogus, must be >= 2)",
585                   vendor_type,
586                   vendor_length));
587            return;
588        }
589        if (vendor_length > length)
590        {
591            ND_PRINT((ndo, "\n\t    Vendor Attribute: %u, Length: %u (bogus, goes past end of vendor-specific attribute)",
592                   vendor_type,
593                   vendor_length));
594            return;
595        }
596        data+=2;
597        vendor_length-=2;
598        length-=2;
599	ND_TCHECK2(*data, vendor_length);
600
601        ND_PRINT((ndo, "\n\t    Vendor Attribute: %u, Length: %u, Value: ",
602               vendor_type,
603               vendor_length));
604        for (idx = 0; idx < vendor_length ; idx++, data++)
605            ND_PRINT((ndo, "%c", (*data < 32 || *data > 126) ? '.' : *data));
606        length-=vendor_length;
607    }
608    return;
609
610   trunc:
611     ND_PRINT((ndo, "%s", tstr));
612}
613
614/******************************/
615/* Print an attribute numeric */
616/* value pointed by 'data'    */
617/* and 'length' size.         */
618/******************************/
619/* Returns nothing.           */
620/******************************/
621static void
622print_attr_num(netdissect_options *ndo,
623               register const u_char *data, u_int length, u_short attr_code)
624{
625   uint32_t timeout;
626
627   if (length != 4)
628   {
629       ND_PRINT((ndo, "ERROR: length %u != 4", length));
630       return;
631   }
632
633   ND_TCHECK2(data[0],4);
634                          /* This attribute has standard values */
635   if (attr_type[attr_code].siz_subtypes)
636   {
637      static const char **table;
638      uint32_t data_value;
639      table = attr_type[attr_code].subtypes;
640
641      if ( (attr_code == TUNNEL_TYPE) || (attr_code == TUNNEL_MEDIUM) )
642      {
643         if (!*data)
644            ND_PRINT((ndo, "Tag[Unused] "));
645         else
646            ND_PRINT((ndo, "Tag[%d] ", *data));
647         data++;
648         data_value = EXTRACT_24BITS(data);
649      }
650      else
651      {
652         data_value = EXTRACT_32BITS(data);
653      }
654      if ( data_value <= (uint32_t)(attr_type[attr_code].siz_subtypes - 1 +
655            attr_type[attr_code].first_subtype) &&
656	   data_value >= attr_type[attr_code].first_subtype )
657         ND_PRINT((ndo, "%s", table[data_value]));
658      else
659         ND_PRINT((ndo, "#%u", data_value));
660   }
661   else
662   {
663      switch(attr_code) /* Be aware of special cases... */
664      {
665        case FRM_IPX:
666             if (EXTRACT_32BITS( data) == 0xFFFFFFFE )
667                ND_PRINT((ndo, "NAS Select"));
668             else
669                ND_PRINT((ndo, "%d", EXTRACT_32BITS(data)));
670          break;
671
672        case SESSION_TIMEOUT:
673        case IDLE_TIMEOUT:
674        case ACCT_DELAY:
675        case ACCT_SESSION_TIME:
676        case ACCT_INT_INTERVAL:
677             timeout = EXTRACT_32BITS( data);
678             if ( timeout < 60 )
679                ND_PRINT((ndo,  "%02d secs", timeout));
680             else
681             {
682                if ( timeout < 3600 )
683                   ND_PRINT((ndo,  "%02d:%02d min",
684                          timeout / 60, timeout % 60));
685                else
686                   ND_PRINT((ndo, "%02d:%02d:%02d hours",
687                          timeout / 3600, (timeout % 3600) / 60,
688                          timeout % 60));
689             }
690          break;
691
692        case FRM_ATALK_LINK:
693             if (EXTRACT_32BITS(data) )
694                ND_PRINT((ndo, "%d", EXTRACT_32BITS(data)));
695             else
696                ND_PRINT((ndo, "Unnumbered"));
697          break;
698
699        case FRM_ATALK_NETWORK:
700             if (EXTRACT_32BITS(data) )
701                ND_PRINT((ndo, "%d", EXTRACT_32BITS(data)));
702             else
703                ND_PRINT((ndo, "NAS assigned"));
704          break;
705
706        case TUNNEL_PREFERENCE:
707            if (*data)
708               ND_PRINT((ndo, "Tag[%d] ", *data));
709            else
710               ND_PRINT((ndo, "Tag[Unused] "));
711            data++;
712            ND_PRINT((ndo, "%d", EXTRACT_24BITS(data)));
713          break;
714
715        case EGRESS_VLAN_ID:
716            ND_PRINT((ndo, "%s (0x%02x) ",
717                   tok2str(rfc4675_tagged,"Unknown tag",*data),
718                   *data));
719            data++;
720            ND_PRINT((ndo, "%d", EXTRACT_24BITS(data)));
721          break;
722
723        default:
724             ND_PRINT((ndo, "%d", EXTRACT_32BITS(data)));
725          break;
726
727      } /* switch */
728
729   } /* if-else */
730
731   return;
732
733   trunc:
734     ND_PRINT((ndo, "%s", tstr));
735}
736
737/*****************************/
738/* Print an attribute IPv4   */
739/* address value pointed by  */
740/* 'data' and 'length' size. */
741/*****************************/
742/* Returns nothing.          */
743/*****************************/
744static void
745print_attr_address(netdissect_options *ndo,
746                   register const u_char *data, u_int length, u_short attr_code)
747{
748   if (length != 4)
749   {
750       ND_PRINT((ndo, "ERROR: length %u != 4", length));
751       return;
752   }
753
754   ND_TCHECK2(data[0],4);
755
756   switch(attr_code)
757   {
758      case FRM_IPADDR:
759      case LOG_IPHOST:
760           if (EXTRACT_32BITS(data) == 0xFFFFFFFF )
761              ND_PRINT((ndo, "User Selected"));
762           else
763              if (EXTRACT_32BITS(data) == 0xFFFFFFFE )
764                 ND_PRINT((ndo, "NAS Select"));
765              else
766                 ND_PRINT((ndo, "%s",ipaddr_string(ndo, data)));
767      break;
768
769      default:
770          ND_PRINT((ndo, "%s", ipaddr_string(ndo, data)));
771      break;
772   }
773
774   return;
775
776   trunc:
777     ND_PRINT((ndo, "%s", tstr));
778}
779
780/*************************************/
781/* Print an attribute of 'secs since */
782/* January 1, 1970 00:00 UTC' value  */
783/* pointed by 'data' and 'length'    */
784/* size.                             */
785/*************************************/
786/* Returns nothing.                  */
787/*************************************/
788static void
789print_attr_time(netdissect_options *ndo,
790                register const u_char *data, u_int length, u_short attr_code _U_)
791{
792   time_t attr_time;
793   char string[26];
794   const char *p;
795
796   if (length != 4)
797   {
798       ND_PRINT((ndo, "ERROR: length %u != 4", length));
799       return;
800   }
801
802   ND_TCHECK2(data[0],4);
803
804   attr_time = EXTRACT_32BITS(data);
805   if ((p = ctime(&attr_time)) == NULL)
806	p = "?";
807   strlcpy(string, p, sizeof(string));
808   /* Get rid of the newline */
809   string[24] = '\0';
810   ND_PRINT((ndo, "%.24s", string));
811   return;
812
813   trunc:
814     ND_PRINT((ndo, "%s", tstr));
815}
816
817/***********************************/
818/* Print an attribute of 'strange' */
819/* data format pointed by 'data'   */
820/* and 'length' size.              */
821/***********************************/
822/* Returns nothing.                */
823/***********************************/
824static void
825print_attr_strange(netdissect_options *ndo,
826                   register const u_char *data, u_int length, u_short attr_code)
827{
828   u_short len_data;
829
830   switch(attr_code)
831   {
832      case ARAP_PASS:
833           if (length != 16)
834           {
835               ND_PRINT((ndo, "ERROR: length %u != 16", length));
836               return;
837           }
838           ND_PRINT((ndo, "User_challenge ("));
839           ND_TCHECK2(data[0],8);
840           len_data = 8;
841           PRINT_HEX(len_data, data);
842           ND_PRINT((ndo, ") User_resp("));
843           ND_TCHECK2(data[0],8);
844           len_data = 8;
845           PRINT_HEX(len_data, data);
846           ND_PRINT((ndo, ")"));
847        break;
848
849      case ARAP_FEATURES:
850           if (length != 14)
851           {
852               ND_PRINT((ndo, "ERROR: length %u != 14", length));
853               return;
854           }
855           ND_TCHECK2(data[0],1);
856           if (*data)
857              ND_PRINT((ndo, "User can change password"));
858           else
859              ND_PRINT((ndo, "User cannot change password"));
860           data++;
861           ND_TCHECK2(data[0],1);
862           ND_PRINT((ndo, ", Min password length: %d", *data));
863           data++;
864           ND_PRINT((ndo, ", created at: "));
865           ND_TCHECK2(data[0],4);
866           len_data = 4;
867           PRINT_HEX(len_data, data);
868           ND_PRINT((ndo, ", expires in: "));
869           ND_TCHECK2(data[0],4);
870           len_data = 4;
871           PRINT_HEX(len_data, data);
872           ND_PRINT((ndo, ", Current Time: "));
873           ND_TCHECK2(data[0],4);
874           len_data = 4;
875           PRINT_HEX(len_data, data);
876        break;
877
878      case ARAP_CHALLENGE_RESP:
879           if (length < 8)
880           {
881               ND_PRINT((ndo, "ERROR: length %u != 8", length));
882               return;
883           }
884           ND_TCHECK2(data[0],8);
885           len_data = 8;
886           PRINT_HEX(len_data, data);
887        break;
888   }
889   return;
890
891   trunc:
892     ND_PRINT((ndo, "%s", tstr));
893}
894
895static void
896radius_attrs_print(netdissect_options *ndo,
897                   register const u_char *attr, u_int length)
898{
899   register const struct radius_attr *rad_attr = (const struct radius_attr *)attr;
900   const char *attr_string;
901
902   while (length > 0)
903   {
904     if (length < 2)
905        goto trunc;
906     ND_TCHECK(*rad_attr);
907
908     if (rad_attr->type > 0 && rad_attr->type < TAM_SIZE(attr_type))
909	attr_string = attr_type[rad_attr->type].name;
910     else
911	attr_string = "Unknown";
912     if (rad_attr->len < 2)
913     {
914	ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u (bogus, must be >= 2)",
915               attr_string,
916               rad_attr->type,
917               rad_attr->len));
918	return;
919     }
920     if (rad_attr->len > length)
921     {
922	ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u (bogus, goes past end of packet)",
923               attr_string,
924               rad_attr->type,
925               rad_attr->len));
926        return;
927     }
928     ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u, Value: ",
929            attr_string,
930            rad_attr->type,
931            rad_attr->len));
932
933     if (rad_attr->type < TAM_SIZE(attr_type))
934     {
935         if (rad_attr->len > 2)
936         {
937             if ( attr_type[rad_attr->type].print_func )
938                 (*attr_type[rad_attr->type].print_func)(
939                     ndo, ((const u_char *)(rad_attr+1)),
940                     rad_attr->len - 2, rad_attr->type);
941         }
942     }
943     /* do we also want to see a hex dump ? */
944     if (ndo->ndo_vflag> 1)
945         print_unknown_data(ndo, (const u_char *)rad_attr+2, "\n\t    ", (rad_attr->len)-2);
946
947     length-=(rad_attr->len);
948     rad_attr = (const struct radius_attr *)( ((const char *)(rad_attr))+rad_attr->len);
949   }
950   return;
951
952trunc:
953   ND_PRINT((ndo, "%s", tstr));
954}
955
956void
957radius_print(netdissect_options *ndo,
958             const u_char *dat, u_int length)
959{
960   register const struct radius_hdr *rad;
961   u_int len, auth_idx;
962
963   ND_TCHECK2(*dat, MIN_RADIUS_LEN);
964   rad = (const struct radius_hdr *)dat;
965   len = EXTRACT_16BITS(&rad->len);
966
967   if (len < MIN_RADIUS_LEN)
968   {
969	  ND_PRINT((ndo, "%s", tstr));
970	  return;
971   }
972
973   if (len > length)
974	  len = length;
975
976   if (ndo->ndo_vflag < 1) {
977       ND_PRINT((ndo, "RADIUS, %s (%u), id: 0x%02x length: %u",
978              tok2str(radius_command_values,"Unknown Command",rad->code),
979              rad->code,
980              rad->id,
981              len));
982       return;
983   }
984   else {
985       ND_PRINT((ndo, "RADIUS, length: %u\n\t%s (%u), id: 0x%02x, Authenticator: ",
986              len,
987              tok2str(radius_command_values,"Unknown Command",rad->code),
988              rad->code,
989              rad->id));
990
991       for(auth_idx=0; auth_idx < 16; auth_idx++)
992            ND_PRINT((ndo, "%02x", rad->auth[auth_idx]));
993   }
994
995   if (len > MIN_RADIUS_LEN)
996      radius_attrs_print(ndo, dat + MIN_RADIUS_LEN, len - MIN_RADIUS_LEN);
997   return;
998
999trunc:
1000   ND_PRINT((ndo, "%s", tstr));
1001}
1002