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