xref: /netbsd-src/external/bsd/tcpdump/dist/print-radius.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
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 /* \summary: Radius protocol printer */
24 
25 /*
26  * Radius printer routines as specified on:
27  *
28  * RFC 2865:
29  *      "Remote Authentication Dial In User Service (RADIUS)"
30  *
31  * RFC 2866:
32  *      "RADIUS Accounting"
33  *
34  * RFC 2867:
35  *      "RADIUS Accounting Modifications for Tunnel Protocol Support"
36  *
37  * RFC 2868:
38  *      "RADIUS Attributes for Tunnel Protocol Support"
39  *
40  * RFC 2869:
41  *      "RADIUS Extensions"
42  *
43  * RFC 3580:
44  *      "IEEE 802.1X Remote Authentication Dial In User Service (RADIUS)"
45  *      "Usage Guidelines"
46  *
47  * RFC 4675:
48  *      "RADIUS Attributes for Virtual LAN and Priority Support"
49  *
50  * RFC 5176:
51  *      "Dynamic Authorization Extensions to RADIUS"
52  *
53  * Alfredo Andres Omella (aandres@s21sec.com) v0.1 2000/09/15
54  *
55  * TODO: Among other things to print ok MacIntosh and Vendor values
56  */
57 
58 #include <sys/cdefs.h>
59 #ifndef lint
60 __RCSID("$NetBSD: print-radius.c,v 1.9 2017/09/08 14:01:13 christos Exp $");
61 #endif
62 
63 #ifdef HAVE_CONFIG_H
64 #include "config.h"
65 #endif
66 
67 #include <netdissect-stdinc.h>
68 
69 #include <string.h>
70 
71 #include "netdissect.h"
72 #include "addrtoname.h"
73 #include "extract.h"
74 #include "oui.h"
75 
76 static const char tstr[] = " [|radius]";
77 
78 #define TAM_SIZE(x) (sizeof(x)/sizeof(x[0]) )
79 
80 #define PRINT_HEX(bytes_len, ptr_data)                               \
81            while(bytes_len)                                          \
82            {                                                         \
83               ND_PRINT((ndo, "%02X", *ptr_data ));                   \
84               ptr_data++;                                            \
85               bytes_len--;                                           \
86            }
87 
88 
89 /* Radius packet codes */
90 #define RADCMD_ACCESS_REQ   1 /* Access-Request      */
91 #define RADCMD_ACCESS_ACC   2 /* Access-Accept       */
92 #define RADCMD_ACCESS_REJ   3 /* Access-Reject       */
93 #define RADCMD_ACCOUN_REQ   4 /* Accounting-Request  */
94 #define RADCMD_ACCOUN_RES   5 /* Accounting-Response */
95 #define RADCMD_ACCESS_CHA  11 /* Access-Challenge    */
96 #define RADCMD_STATUS_SER  12 /* Status-Server       */
97 #define RADCMD_STATUS_CLI  13 /* Status-Client       */
98 #define RADCMD_DISCON_REQ  40 /* Disconnect-Request  */
99 #define RADCMD_DISCON_ACK  41 /* Disconnect-ACK      */
100 #define RADCMD_DISCON_NAK  42 /* Disconnect-NAK      */
101 #define RADCMD_COA_REQ     43 /* CoA-Request         */
102 #define RADCMD_COA_ACK     44 /* CoA-ACK             */
103 #define RADCMD_COA_NAK     45 /* CoA-NAK             */
104 #define RADCMD_RESERVED   255 /* Reserved            */
105 
106 static const struct tok radius_command_values[] = {
107     { RADCMD_ACCESS_REQ, "Access-Request" },
108     { RADCMD_ACCESS_ACC, "Access-Accept" },
109     { RADCMD_ACCESS_REJ, "Access-Reject" },
110     { RADCMD_ACCOUN_REQ, "Accounting-Request" },
111     { RADCMD_ACCOUN_RES, "Accounting-Response" },
112     { RADCMD_ACCESS_CHA, "Access-Challenge" },
113     { RADCMD_STATUS_SER, "Status-Server" },
114     { RADCMD_STATUS_CLI, "Status-Client" },
115     { RADCMD_DISCON_REQ, "Disconnect-Request" },
116     { RADCMD_DISCON_ACK, "Disconnect-ACK" },
117     { RADCMD_DISCON_NAK, "Disconnect-NAK" },
118     { RADCMD_COA_REQ,    "CoA-Request" },
119     { RADCMD_COA_ACK,    "CoA-ACK" },
120     { RADCMD_COA_NAK,    "CoA-NAK" },
121     { RADCMD_RESERVED,   "Reserved" },
122     { 0, NULL}
123 };
124 
125 /********************************/
126 /* Begin Radius Attribute types */
127 /********************************/
128 #define SERV_TYPE    6
129 #define FRM_IPADDR   8
130 #define LOG_IPHOST  14
131 #define LOG_SERVICE 15
132 #define FRM_IPX     23
133 #define SESSION_TIMEOUT   27
134 #define IDLE_TIMEOUT      28
135 #define FRM_ATALK_LINK    37
136 #define FRM_ATALK_NETWORK 38
137 
138 #define ACCT_DELAY        41
139 #define ACCT_SESSION_TIME 46
140 
141 #define EGRESS_VLAN_ID   56
142 #define EGRESS_VLAN_NAME 58
143 
144 #define TUNNEL_TYPE        64
145 #define TUNNEL_MEDIUM      65
146 #define TUNNEL_CLIENT_END  66
147 #define TUNNEL_SERVER_END  67
148 #define TUNNEL_PASS        69
149 
150 #define ARAP_PASS          70
151 #define ARAP_FEATURES      71
152 
153 #define TUNNEL_PRIV_GROUP  81
154 #define TUNNEL_ASSIGN_ID   82
155 #define TUNNEL_PREFERENCE  83
156 
157 #define ARAP_CHALLENGE_RESP 84
158 #define ACCT_INT_INTERVAL   85
159 
160 #define TUNNEL_CLIENT_AUTH 90
161 #define TUNNEL_SERVER_AUTH 91
162 /********************************/
163 /* End Radius Attribute types */
164 /********************************/
165 
166 #define RFC4675_TAGGED   0x31
167 #define RFC4675_UNTAGGED 0x32
168 
169 static const struct tok rfc4675_tagged[] = {
170     { RFC4675_TAGGED,   "Tagged" },
171     { RFC4675_UNTAGGED, "Untagged" },
172     { 0, NULL}
173 };
174 
175 
176 static void print_attr_string(netdissect_options *, register const u_char *, u_int, u_short );
177 static void print_attr_num(netdissect_options *, register const u_char *, u_int, u_short );
178 static void print_vendor_attr(netdissect_options *, register const u_char *, u_int, u_short );
179 static void print_attr_address(netdissect_options *, register const u_char *, u_int, u_short);
180 static void print_attr_time(netdissect_options *, register const u_char *, u_int, u_short);
181 static void print_attr_strange(netdissect_options *, register const u_char *, u_int, u_short);
182 
183 
184 struct radius_hdr { uint8_t  code; /* Radius packet code  */
185                     uint8_t  id;   /* Radius packet id    */
186                     uint16_t len;  /* Radius total length */
187                     uint8_t  auth[16]; /* Authenticator   */
188                   };
189 
190 #define MIN_RADIUS_LEN	20
191 
192 struct radius_attr { uint8_t type; /* Attribute type   */
193                      uint8_t len;  /* Attribute length */
194                    };
195 
196 
197 /* Service-Type Attribute standard values */
198 static const char *serv_type[]={ NULL,
199                                 "Login",
200                                 "Framed",
201                                 "Callback Login",
202                                 "Callback Framed",
203                                 "Outbound",
204                                 "Administrative",
205                                 "NAS Prompt",
206                                 "Authenticate Only",
207                                 "Callback NAS Prompt",
208                                 "Call Check",
209                                 "Callback Administrative",
210                                };
211 
212 /* Framed-Protocol Attribute standard values */
213 static const char *frm_proto[]={ NULL,
214                                  "PPP",
215                                  "SLIP",
216                                  "ARAP",
217                                  "Gandalf proprietary",
218                                  "Xylogics IPX/SLIP",
219                                  "X.75 Synchronous",
220                                };
221 
222 /* Framed-Routing Attribute standard values */
223 static const char *frm_routing[]={ "None",
224                                    "Send",
225                                    "Listen",
226                                    "Send&Listen",
227                                  };
228 
229 /* Framed-Compression Attribute standard values */
230 static const char *frm_comp[]={ "None",
231                                 "VJ TCP/IP",
232                                 "IPX",
233                                 "Stac-LZS",
234                               };
235 
236 /* Login-Service Attribute standard values */
237 static const char *login_serv[]={ "Telnet",
238                                   "Rlogin",
239                                   "TCP Clear",
240                                   "PortMaster(proprietary)",
241                                   "LAT",
242                                   "X.25-PAD",
243                                   "X.25-T3POS",
244                                   "Unassigned",
245                                   "TCP Clear Quiet",
246                                 };
247 
248 
249 /* Termination-Action Attribute standard values */
250 static const char *term_action[]={ "Default",
251                                    "RADIUS-Request",
252                                  };
253 
254 /* Ingress-Filters Attribute standard values */
255 static const char *ingress_filters[]={ NULL,
256                                        "Enabled",
257                                        "Disabled",
258                                      };
259 
260 /* NAS-Port-Type Attribute standard values */
261 static const char *nas_port_type[]={ "Async",
262                                      "Sync",
263                                      "ISDN Sync",
264                                      "ISDN Async V.120",
265                                      "ISDN Async V.110",
266                                      "Virtual",
267                                      "PIAFS",
268                                      "HDLC Clear Channel",
269                                      "X.25",
270                                      "X.75",
271                                      "G.3 Fax",
272                                      "SDSL",
273                                      "ADSL-CAP",
274                                      "ADSL-DMT",
275                                      "ISDN-DSL",
276                                      "Ethernet",
277                                      "xDSL",
278                                      "Cable",
279                                      "Wireless - Other",
280                                      "Wireless - IEEE 802.11",
281                                    };
282 
283 /* Acct-Status-Type Accounting Attribute standard values */
284 static const char *acct_status[]={ NULL,
285                                    "Start",
286                                    "Stop",
287                                    "Interim-Update",
288                                    "Unassigned",
289                                    "Unassigned",
290                                    "Unassigned",
291                                    "Accounting-On",
292                                    "Accounting-Off",
293                                    "Tunnel-Start",
294                                    "Tunnel-Stop",
295                                    "Tunnel-Reject",
296                                    "Tunnel-Link-Start",
297                                    "Tunnel-Link-Stop",
298                                    "Tunnel-Link-Reject",
299                                    "Failed",
300                                  };
301 
302 /* Acct-Authentic Accounting Attribute standard values */
303 static const char *acct_auth[]={ NULL,
304                                  "RADIUS",
305                                  "Local",
306                                  "Remote",
307                                };
308 
309 /* Acct-Terminate-Cause Accounting Attribute standard values */
310 static const char *acct_term[]={ NULL,
311                                  "User Request",
312                                  "Lost Carrier",
313                                  "Lost Service",
314                                  "Idle Timeout",
315                                  "Session Timeout",
316                                  "Admin Reset",
317                                  "Admin Reboot",
318                                  "Port Error",
319                                  "NAS Error",
320                                  "NAS Request",
321                                  "NAS Reboot",
322                                  "Port Unneeded",
323                                  "Port Preempted",
324                                  "Port Suspended",
325                                  "Service Unavailable",
326                                  "Callback",
327                                  "User Error",
328                                  "Host Request",
329                                };
330 
331 /* Tunnel-Type Attribute standard values */
332 static const char *tunnel_type[]={ NULL,
333                                    "PPTP",
334                                    "L2F",
335                                    "L2TP",
336                                    "ATMP",
337                                    "VTP",
338                                    "AH",
339                                    "IP-IP",
340                                    "MIN-IP-IP",
341                                    "ESP",
342                                    "GRE",
343                                    "DVS",
344                                    "IP-in-IP Tunneling",
345                                    "VLAN",
346                                  };
347 
348 /* Tunnel-Medium-Type Attribute standard values */
349 static const char *tunnel_medium[]={ NULL,
350                                      "IPv4",
351                                      "IPv6",
352                                      "NSAP",
353                                      "HDLC",
354                                      "BBN 1822",
355                                      "802",
356                                      "E.163",
357                                      "E.164",
358                                      "F.69",
359                                      "X.121",
360                                      "IPX",
361                                      "Appletalk",
362                                      "Decnet IV",
363                                      "Banyan Vines",
364                                      "E.164 with NSAP subaddress",
365                                    };
366 
367 /* ARAP-Zone-Access Attribute standard values */
368 static const char *arap_zone[]={ NULL,
369                                  "Only access to dfl zone",
370                                  "Use zone filter inc.",
371                                  "Not used",
372                                  "Use zone filter exc.",
373                                };
374 
375 static const char *prompt[]={ "No Echo",
376                               "Echo",
377                             };
378 
379 
380 static struct attrtype {
381                   const char *name;      /* Attribute name                 */
382                   const char **subtypes; /* Standard Values (if any)       */
383                   u_char siz_subtypes;   /* Size of total standard values  */
384                   u_char first_subtype;  /* First standard value is 0 or 1 */
385                   void (*print_func)(netdissect_options *, register const u_char *, u_int, u_short);
386                 } attr_type[]=
387   {
388      { NULL,                              NULL, 0, 0, NULL               },
389      { "User-Name",                       NULL, 0, 0, print_attr_string  },
390      { "User-Password",                   NULL, 0, 0, NULL               },
391      { "CHAP-Password",                   NULL, 0, 0, NULL               },
392      { "NAS-IP-Address",                  NULL, 0, 0, print_attr_address },
393      { "NAS-Port",                        NULL, 0, 0, print_attr_num     },
394      { "Service-Type",                    serv_type, TAM_SIZE(serv_type)-1, 1, print_attr_num },
395      { "Framed-Protocol",                 frm_proto, TAM_SIZE(frm_proto)-1, 1, print_attr_num },
396      { "Framed-IP-Address",               NULL, 0, 0, print_attr_address },
397      { "Framed-IP-Netmask",               NULL, 0, 0, print_attr_address },
398      { "Framed-Routing",                  frm_routing, TAM_SIZE(frm_routing), 0, print_attr_num },
399      { "Filter-Id",                       NULL, 0, 0, print_attr_string  },
400      { "Framed-MTU",                      NULL, 0, 0, print_attr_num     },
401      { "Framed-Compression",              frm_comp, TAM_SIZE(frm_comp),   0, print_attr_num },
402      { "Login-IP-Host",                   NULL, 0, 0, print_attr_address },
403      { "Login-Service",                   login_serv, TAM_SIZE(login_serv), 0, print_attr_num },
404      { "Login-TCP-Port",                  NULL, 0, 0, print_attr_num     },
405      { "Unassigned",                      NULL, 0, 0, NULL }, /*17*/
406      { "Reply-Message",                   NULL, 0, 0, print_attr_string },
407      { "Callback-Number",                 NULL, 0, 0, print_attr_string },
408      { "Callback-Id",                     NULL, 0, 0, print_attr_string },
409      { "Unassigned",                      NULL, 0, 0, NULL }, /*21*/
410      { "Framed-Route",                    NULL, 0, 0, print_attr_string },
411      { "Framed-IPX-Network",              NULL, 0, 0, print_attr_num    },
412      { "State",                           NULL, 0, 0, print_attr_string },
413      { "Class",                           NULL, 0, 0, print_attr_string },
414      { "Vendor-Specific",                 NULL, 0, 0, print_vendor_attr },
415      { "Session-Timeout",                 NULL, 0, 0, print_attr_num    },
416      { "Idle-Timeout",                    NULL, 0, 0, print_attr_num    },
417      { "Termination-Action",              term_action, TAM_SIZE(term_action), 0, print_attr_num },
418      { "Called-Station-Id",               NULL, 0, 0, print_attr_string },
419      { "Calling-Station-Id",              NULL, 0, 0, print_attr_string },
420      { "NAS-Identifier",                  NULL, 0, 0, print_attr_string },
421      { "Proxy-State",                     NULL, 0, 0, print_attr_string },
422      { "Login-LAT-Service",               NULL, 0, 0, print_attr_string },
423      { "Login-LAT-Node",                  NULL, 0, 0, print_attr_string },
424      { "Login-LAT-Group",                 NULL, 0, 0, print_attr_string },
425      { "Framed-AppleTalk-Link",           NULL, 0, 0, print_attr_num    },
426      { "Framed-AppleTalk-Network",        NULL, 0, 0, print_attr_num    },
427      { "Framed-AppleTalk-Zone",           NULL, 0, 0, print_attr_string },
428      { "Acct-Status-Type",                acct_status, TAM_SIZE(acct_status)-1, 1, print_attr_num },
429      { "Acct-Delay-Time",                 NULL, 0, 0, print_attr_num    },
430      { "Acct-Input-Octets",               NULL, 0, 0, print_attr_num    },
431      { "Acct-Output-Octets",              NULL, 0, 0, print_attr_num    },
432      { "Acct-Session-Id",                 NULL, 0, 0, print_attr_string },
433      { "Acct-Authentic",                  acct_auth, TAM_SIZE(acct_auth)-1, 1, print_attr_num },
434      { "Acct-Session-Time",               NULL, 0, 0, print_attr_num },
435      { "Acct-Input-Packets",              NULL, 0, 0, print_attr_num },
436      { "Acct-Output-Packets",             NULL, 0, 0, print_attr_num },
437      { "Acct-Terminate-Cause",            acct_term, TAM_SIZE(acct_term)-1, 1, print_attr_num },
438      { "Acct-Multi-Session-Id",           NULL, 0, 0, print_attr_string },
439      { "Acct-Link-Count",                 NULL, 0, 0, print_attr_num },
440      { "Acct-Input-Gigawords",            NULL, 0, 0, print_attr_num },
441      { "Acct-Output-Gigawords",           NULL, 0, 0, print_attr_num },
442      { "Unassigned",                      NULL, 0, 0, NULL }, /*54*/
443      { "Event-Timestamp",                 NULL, 0, 0, print_attr_time },
444      { "Egress-VLANID",                   NULL, 0, 0, print_attr_num },
445      { "Ingress-Filters",                 ingress_filters, TAM_SIZE(ingress_filters)-1, 1, print_attr_num },
446      { "Egress-VLAN-Name",                NULL, 0, 0, print_attr_string },
447      { "User-Priority-Table",             NULL, 0, 0, NULL },
448      { "CHAP-Challenge",                  NULL, 0, 0, print_attr_string },
449      { "NAS-Port-Type",                   nas_port_type, TAM_SIZE(nas_port_type), 0, print_attr_num },
450      { "Port-Limit",                      NULL, 0, 0, print_attr_num },
451      { "Login-LAT-Port",                  NULL, 0, 0, print_attr_string }, /*63*/
452      { "Tunnel-Type",                     tunnel_type, TAM_SIZE(tunnel_type)-1, 1, print_attr_num },
453      { "Tunnel-Medium-Type",              tunnel_medium, TAM_SIZE(tunnel_medium)-1, 1, print_attr_num },
454      { "Tunnel-Client-Endpoint",          NULL, 0, 0, print_attr_string },
455      { "Tunnel-Server-Endpoint",          NULL, 0, 0, print_attr_string },
456      { "Acct-Tunnel-Connection",          NULL, 0, 0, print_attr_string },
457      { "Tunnel-Password",                 NULL, 0, 0, print_attr_string  },
458      { "ARAP-Password",                   NULL, 0, 0, print_attr_strange },
459      { "ARAP-Features",                   NULL, 0, 0, print_attr_strange },
460      { "ARAP-Zone-Access",                arap_zone, TAM_SIZE(arap_zone)-1, 1, print_attr_num }, /*72*/
461      { "ARAP-Security",                   NULL, 0, 0, print_attr_string },
462      { "ARAP-Security-Data",              NULL, 0, 0, print_attr_string },
463      { "Password-Retry",                  NULL, 0, 0, print_attr_num    },
464      { "Prompt",                          prompt, TAM_SIZE(prompt), 0, print_attr_num },
465      { "Connect-Info",                    NULL, 0, 0, print_attr_string   },
466      { "Configuration-Token",             NULL, 0, 0, print_attr_string   },
467      { "EAP-Message",                     NULL, 0, 0, print_attr_string   },
468      { "Message-Authenticator",           NULL, 0, 0, print_attr_string }, /*80*/
469      { "Tunnel-Private-Group-ID",         NULL, 0, 0, print_attr_string },
470      { "Tunnel-Assignment-ID",            NULL, 0, 0, print_attr_string },
471      { "Tunnel-Preference",               NULL, 0, 0, print_attr_num    },
472      { "ARAP-Challenge-Response",         NULL, 0, 0, print_attr_strange },
473      { "Acct-Interim-Interval",           NULL, 0, 0, print_attr_num     },
474      { "Acct-Tunnel-Packets-Lost",        NULL, 0, 0, print_attr_num }, /*86*/
475      { "NAS-Port-Id",                     NULL, 0, 0, print_attr_string },
476      { "Framed-Pool",                     NULL, 0, 0, print_attr_string },
477      { "CUI",                             NULL, 0, 0, print_attr_string },
478      { "Tunnel-Client-Auth-ID",           NULL, 0, 0, print_attr_string },
479      { "Tunnel-Server-Auth-ID",           NULL, 0, 0, print_attr_string },
480      { "Unassigned",                      NULL, 0, 0, NULL }, /*92*/
481      { "Unassigned",                      NULL, 0, 0, NULL }  /*93*/
482   };
483 
484 
485 /*****************************/
486 /* Print an attribute string */
487 /* value pointed by 'data'   */
488 /* and 'length' size.        */
489 /*****************************/
490 /* Returns nothing.          */
491 /*****************************/
492 static void
493 print_attr_string(netdissect_options *ndo,
494                   register const u_char *data, u_int length, u_short attr_code)
495 {
496    register u_int i;
497 
498    ND_TCHECK2(data[0],length);
499 
500    switch(attr_code)
501    {
502       case TUNNEL_PASS:
503            if (length < 3)
504               goto trunc;
505            if (*data && (*data <=0x1F) )
506               ND_PRINT((ndo, "Tag[%u] ", *data));
507            else
508               ND_PRINT((ndo, "Tag[Unused] "));
509            data++;
510            length--;
511            ND_PRINT((ndo, "Salt %u ", EXTRACT_16BITS(data)));
512            data+=2;
513            length-=2;
514         break;
515       case TUNNEL_CLIENT_END:
516       case TUNNEL_SERVER_END:
517       case TUNNEL_PRIV_GROUP:
518       case TUNNEL_ASSIGN_ID:
519       case TUNNEL_CLIENT_AUTH:
520       case TUNNEL_SERVER_AUTH:
521            if (*data <= 0x1F)
522            {
523               if (length < 1)
524                  goto trunc;
525               if (*data)
526                 ND_PRINT((ndo, "Tag[%u] ", *data));
527               else
528                 ND_PRINT((ndo, "Tag[Unused] "));
529               data++;
530               length--;
531            }
532         break;
533       case EGRESS_VLAN_NAME:
534            if (length < 1)
535               goto trunc;
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; i < length && *data; 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  */
556 static void
557 print_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 /******************************/
621 static void
622 print_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 /*****************************/
744 static void
745 print_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 /*************************************/
788 static void
789 print_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 /***********************************/
824 static void
825 print_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 
895 static void
896 radius_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 
952 trunc:
953    ND_PRINT((ndo, "%s", tstr));
954 }
955 
956 void
957 radius_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 
999 trunc:
1000    ND_PRINT((ndo, "%s", tstr));
1001 }
1002