Home | History | Annotate | Line # | Download | only in dist
print-radius.c revision 1.5
      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 (at) 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    const char *p;
    731 
    732    if (length != 4)
    733    {
    734        ND_PRINT((ndo, "ERROR: length %u != 4", length));
    735        return;
    736    }
    737 
    738    ND_TCHECK2(data[0],4);
    739 
    740    attr_time = EXTRACT_32BITS(data);
    741    if ((p = ctime(&attr_time)) == NULL)
    742 	p = "?";
    743    strlcpy(string, p, sizeof(string));
    744    /* Get rid of the newline */
    745    string[24] = '\0';
    746    ND_PRINT((ndo, "%.24s", string));
    747    return;
    748 
    749    trunc:
    750      ND_PRINT((ndo, "%s", tstr));
    751 }
    752 
    753 /***********************************/
    754 /* Print an attribute of 'strange' */
    755 /* data format pointed by 'data'   */
    756 /* and 'length' size.              */
    757 /***********************************/
    758 /* Returns nothing.                */
    759 /***********************************/
    760 static void
    761 print_attr_strange(netdissect_options *ndo,
    762                    register u_char *data, u_int length, u_short attr_code)
    763 {
    764    u_short len_data;
    765 
    766    switch(attr_code)
    767    {
    768       case ARAP_PASS:
    769            if (length != 16)
    770            {
    771                ND_PRINT((ndo, "ERROR: length %u != 16", length));
    772                return;
    773            }
    774            ND_PRINT((ndo, "User_challenge ("));
    775            ND_TCHECK2(data[0],8);
    776            len_data = 8;
    777            PRINT_HEX(len_data, data);
    778            ND_PRINT((ndo, ") User_resp("));
    779            ND_TCHECK2(data[0],8);
    780            len_data = 8;
    781            PRINT_HEX(len_data, data);
    782            ND_PRINT((ndo, ")"));
    783         break;
    784 
    785       case ARAP_FEATURES:
    786            if (length != 14)
    787            {
    788                ND_PRINT((ndo, "ERROR: length %u != 14", length));
    789                return;
    790            }
    791            ND_TCHECK2(data[0],1);
    792            if (*data)
    793               ND_PRINT((ndo, "User can change password"));
    794            else
    795               ND_PRINT((ndo, "User cannot change password"));
    796            data++;
    797            ND_TCHECK2(data[0],1);
    798            ND_PRINT((ndo, ", Min password length: %d", *data));
    799            data++;
    800            ND_PRINT((ndo, ", created at: "));
    801            ND_TCHECK2(data[0],4);
    802            len_data = 4;
    803            PRINT_HEX(len_data, data);
    804            ND_PRINT((ndo, ", expires in: "));
    805            ND_TCHECK2(data[0],4);
    806            len_data = 4;
    807            PRINT_HEX(len_data, data);
    808            ND_PRINT((ndo, ", Current Time: "));
    809            ND_TCHECK2(data[0],4);
    810            len_data = 4;
    811            PRINT_HEX(len_data, data);
    812         break;
    813 
    814       case ARAP_CHALLENGE_RESP:
    815            if (length < 8)
    816            {
    817                ND_PRINT((ndo, "ERROR: length %u != 8", length));
    818                return;
    819            }
    820            ND_TCHECK2(data[0],8);
    821            len_data = 8;
    822            PRINT_HEX(len_data, data);
    823         break;
    824    }
    825    return;
    826 
    827    trunc:
    828      ND_PRINT((ndo, "%s", tstr));
    829 }
    830 
    831 static void
    832 radius_attrs_print(netdissect_options *ndo,
    833                    register const u_char *attr, u_int length)
    834 {
    835    register const struct radius_attr *rad_attr = (struct radius_attr *)attr;
    836    const char *attr_string;
    837 
    838    while (length > 0)
    839    {
    840      if (length < 2)
    841         goto trunc;
    842      ND_TCHECK(*rad_attr);
    843 
    844      if (rad_attr->type > 0 && rad_attr->type < TAM_SIZE(attr_type))
    845 	attr_string = attr_type[rad_attr->type].name;
    846      else
    847 	attr_string = "Unknown";
    848      if (rad_attr->len < 2)
    849      {
    850 	ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u (bogus, must be >= 2)",
    851                attr_string,
    852                rad_attr->type,
    853                rad_attr->len));
    854 	return;
    855      }
    856      if (rad_attr->len > length)
    857      {
    858 	ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u (bogus, goes past end of packet)",
    859                attr_string,
    860                rad_attr->type,
    861                rad_attr->len));
    862         return;
    863      }
    864      ND_PRINT((ndo, "\n\t  %s Attribute (%u), length: %u, Value: ",
    865             attr_string,
    866             rad_attr->type,
    867             rad_attr->len));
    868 
    869      if (rad_attr->type < TAM_SIZE(attr_type))
    870      {
    871          if (rad_attr->len > 2)
    872          {
    873              if ( attr_type[rad_attr->type].print_func )
    874                  (*attr_type[rad_attr->type].print_func)(
    875                      ndo, ((u_char *)(rad_attr+1)),
    876                      rad_attr->len - 2, rad_attr->type);
    877          }
    878      }
    879      /* do we also want to see a hex dump ? */
    880      if (ndo->ndo_vflag> 1)
    881          print_unknown_data(ndo, (u_char *)rad_attr+2, "\n\t    ", (rad_attr->len)-2);
    882 
    883      length-=(rad_attr->len);
    884      rad_attr = (struct radius_attr *)( ((char *)(rad_attr))+rad_attr->len);
    885    }
    886    return;
    887 
    888 trunc:
    889    ND_PRINT((ndo, "%s", tstr));
    890 }
    891 
    892 void
    893 radius_print(netdissect_options *ndo,
    894              const u_char *dat, u_int length)
    895 {
    896    register const struct radius_hdr *rad;
    897    u_int len, auth_idx;
    898 
    899    ND_TCHECK2(*dat, MIN_RADIUS_LEN);
    900    rad = (struct radius_hdr *)dat;
    901    len = EXTRACT_16BITS(&rad->len);
    902 
    903    if (len < MIN_RADIUS_LEN)
    904    {
    905 	  ND_PRINT((ndo, "%s", tstr));
    906 	  return;
    907    }
    908 
    909    if (len > length)
    910 	  len = length;
    911 
    912    if (ndo->ndo_vflag < 1) {
    913        ND_PRINT((ndo, "RADIUS, %s (%u), id: 0x%02x length: %u",
    914               tok2str(radius_command_values,"Unknown Command",rad->code),
    915               rad->code,
    916               rad->id,
    917               len));
    918        return;
    919    }
    920    else {
    921        ND_PRINT((ndo, "RADIUS, length: %u\n\t%s (%u), id: 0x%02x, Authenticator: ",
    922               len,
    923               tok2str(radius_command_values,"Unknown Command",rad->code),
    924               rad->code,
    925               rad->id));
    926 
    927        for(auth_idx=0; auth_idx < 16; auth_idx++)
    928             ND_PRINT((ndo, "%02x", rad->auth[auth_idx]));
    929    }
    930 
    931    if (len > MIN_RADIUS_LEN)
    932       radius_attrs_print(ndo, dat + MIN_RADIUS_LEN, len - MIN_RADIUS_LEN);
    933    return;
    934 
    935 trunc:
    936    ND_PRINT((ndo, "%s", tstr));
    937 }
    938