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