1 /* $OpenBSD: print-radius.c,v 1.11 2015/11/16 00:16:39 mmcc Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Thomas H. Ptacek. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/types.h> 31 #include <netinet/in.h> 32 #include <arpa/inet.h> 33 34 #include <stdio.h> 35 #include <string.h> 36 37 /* RADIUS support for tcpdump, Thomas Ptacek <tqbf@enteract.com> */ 38 39 #include "interface.h" 40 #include "radius.h" 41 42 static void r_print_att(int code, int len, const u_char *val); 43 static void r_print_int(int code, int len, const u_char *val); 44 static void r_print_address(int code, int len, const u_char *val); 45 static void r_print_string(int code, int len, const u_char *val); 46 static void r_print_hex(int code, int len, const u_char *val); 47 48 /* --------------------------------------------------------------- */ 49 50 struct radius_ctable { 51 int code; 52 char *name; 53 }; 54 55 /* map opcodes to strings */ 56 57 #define DEFINED_OPCODES 11 58 59 static struct radius_ctable radius_codes[] = { 60 { -1, NULL }, 61 { RADIUS_CODE_ACCESS_REQUEST, "Axs?" }, 62 { RADIUS_CODE_ACCESS_ACCEPT, "Axs+" }, 63 { RADIUS_CODE_ACCESS_REJECT, "Axs-" }, 64 { RADIUS_CODE_ACCOUNT_REQUEST, "Act?" }, 65 { RADIUS_CODE_ACCOUNT_RESPONSE, "Act+" }, 66 { RADIUS_CODE_ACCOUNT_STATUS, "ActSt" }, 67 { RADIUS_CODE_PASSCHG_REQUEST, "Pchg?" }, 68 { RADIUS_CODE_PASSCHG_ACCEPT, "Pchg+" }, 69 { RADIUS_CODE_PASSCHG_REJECT, "Pchg-" }, 70 { RADIUS_CODE_ACCOUNT_MESSAGE, "ActMg" }, 71 { RADIUS_CODE_ACCESS_CHALLENGE, "Axs!" }, 72 { -1, NULL } 73 }; 74 75 /* --------------------------------------------------------------- */ 76 77 #define MAX_VALUES 20 78 79 struct radius_atable { 80 int code; 81 int encoding; 82 char *name; 83 char *values[MAX_VALUES]; 84 }; 85 86 /* map attributes to strings */ 87 88 /* the right way to do this is probably to read these values out 89 * of the actual RADIUS dictionary; this would require the machine 90 * running tcpdump to have that file installed, and it's not my 91 * program, so I'm not going to introduce new dependencies. Oh well. 92 */ 93 94 static struct radius_atable radius_atts[] = { 95 96 { RADIUS_ATT_USER_NAME, RD_STRING, "Name", { NULL } }, 97 { RADIUS_ATT_PASSWORD, RD_HEX, "Pass", { NULL } }, 98 { RADIUS_ATT_CHAP_PASS, RD_HEX, "CPass", { NULL } }, 99 { RADIUS_ATT_NAS_IP, RD_ADDRESS, "NAS-IP", { NULL } }, 100 { RADIUS_ATT_NAS_PORT, RD_INT, "NAS-Pt", { NULL } }, 101 102 { RADIUS_ATT_USER_SERVICE, RD_INT, "USvc", 103 { "", "Login", "Framed", "DB-Lgn", "DB-Frm", "Out", "Shell", NULL } }, 104 105 { RADIUS_ATT_PROTOCOL, RD_INT, "FProt", 106 { "", "PPP", "SLIP", NULL } }, 107 108 { RADIUS_ATT_FRAMED_ADDRESS, RD_ADDRESS, "F-IP", { NULL } }, 109 { RADIUS_ATT_NETMASK, RD_ADDRESS, "F-Msk", { NULL } }, 110 { RADIUS_ATT_ROUTING, RD_INT, "F-Rtg", { NULL } }, 111 { RADIUS_ATT_FILTER, RD_STRING, "FltID", { NULL } }, 112 { RADIUS_ATT_MTU, RD_INT, "F-MTU", { NULL } }, 113 { RADIUS_ATT_COMPRESSION, RD_INT, "F-Comp", { NULL } }, 114 { RADIUS_ATT_LOGIN_HOST, RD_ADDRESS, "L-Hst", { NULL } }, 115 116 { RADIUS_ATT_LOGIN_SERVICE, RD_INT, "L-Svc", 117 { "", "Telnt", "Rlog", "Clear", "PortM", NULL } }, 118 119 { RADIUS_ATT_LOGIN_TCP_PORT, RD_INT, "L-Pt", { NULL } }, 120 { RADIUS_ATT_OLD_PASSWORD, RD_HEX, "OPass", { NULL } }, 121 { RADIUS_ATT_PORT_MESSAGE, RD_STRING, "PMsg", { NULL } }, 122 { RADIUS_ATT_DIALBACK_NO, RD_STRING, "DB#", { NULL } }, 123 { RADIUS_ATT_DIALBACK_NAME, RD_STRING, "DBNm", { NULL } }, 124 { RADIUS_ATT_EXPIRATION, RD_DATE, "PExp", { NULL } }, 125 { RADIUS_ATT_FRAMED_ROUTE, RD_STRING, "F-Rt", { NULL } }, 126 { RADIUS_ATT_FRAMED_IPX, RD_ADDRESS, "F-IPX", { NULL } }, 127 { RADIUS_ATT_CHALLENGE_STATE, RD_STRING, "CState", { NULL } }, 128 { RADIUS_ATT_CLASS, RD_STRING, "Class", { NULL } }, 129 { RADIUS_ATT_VENDOR_SPECIFIC, RD_HEX, "Vendor", { NULL } }, 130 { RADIUS_ATT_SESSION_TIMEOUT, RD_INT, "S-TO", { NULL } }, 131 { RADIUS_ATT_IDLE_TIMEOUT, RD_INT, "I-TO", { NULL } }, 132 { RADIUS_ATT_TERMINATE_ACTION, RD_INT, "TermAct", { NULL } }, 133 { RADIUS_ATT_CALLED_ID, RD_STRING, "Callee", { NULL } }, 134 { RADIUS_ATT_CALLER_ID, RD_STRING, "Caller", { NULL } }, 135 136 { RADIUS_ATT_STATUS_TYPE, RD_INT, "Stat", 137 { "", "Start", "Stop", NULL } }, 138 139 { -1, -1, NULL, { NULL } } 140 141 }; 142 143 typedef void (*aselector)(int code, int len, const u_char *data); 144 aselector atselector[] = { 145 r_print_hex, 146 r_print_int, 147 r_print_int, 148 r_print_address, 149 r_print_string, 150 r_print_hex 151 }; 152 153 static void r_print_att(int code, int len, const u_char *data) { 154 struct radius_atable *atp; 155 int i; 156 157 for(atp = radius_atts; atp->code != -1; atp++) 158 if(atp->code == code) 159 break; 160 161 if(atp->code == -1) { 162 if(vflag > 1) { 163 fprintf(stdout, " %d =", code); 164 atselector[RD_HEX](code, len, data); 165 } else 166 fprintf(stdout, " %d", code); 167 168 return; 169 } 170 171 fprintf(stdout, " %s =", atp->name); 172 173 if(atp->encoding == RD_INT && *atp->values) { 174 u_int32_t k = ntohl((*(int *)data)); 175 176 for(i = 0; atp->values[i] != NULL; i++) 177 /* SHOOT ME */ ; 178 179 if(k < i) { 180 fprintf(stdout, " %s", 181 atp->values[k]); 182 return; 183 } 184 } 185 186 atselector[atp->encoding](code, len, data); 187 } 188 189 static void r_print_int(int code, int len, const u_char *data) { 190 if(len < 4) { 191 fputs(" ?", stdout); 192 return; 193 } 194 195 fprintf(stdout, " %d", ntohl((*(int *)data))); 196 } 197 198 static void r_print_address(int code, int len, const u_char *data) { 199 if(len < 4) { 200 fputs(" ?", stdout); 201 return; 202 } 203 204 fprintf(stdout, " %s", inet_ntoa((*(struct in_addr *)data))); 205 } 206 207 static void r_print_string(int code, int len, const u_char *data) { 208 char string[128]; 209 210 if(!len) { 211 fputs(" ?", stdout); 212 return; 213 } 214 215 if(len > 127) 216 len = 127; 217 218 memset(string, 0, 128); 219 memcpy(string, data, len); 220 221 fprintf(stdout, " "); 222 safeputs(string); 223 } 224 225 static void r_print_hex(int code, int len, const u_char *data) { 226 int i; 227 228 /* excuse me */ 229 230 fputs(" [", stdout); 231 232 for(i = 0; i < len; i++) 233 fprintf(stdout, "%02x", data[i]); 234 235 fputc(']', stdout); 236 } 237 238 void radius_print(const u_char *data, u_int len) { 239 const struct radius_header *rhp; 240 const u_char *pp; 241 int first, l, ac, al; 242 243 if(len < sizeof(struct radius_header)) { 244 fputs(" [|radius]", stdout); 245 return; 246 } 247 248 rhp = (struct radius_header *) data; 249 250 if(rhp->code > DEFINED_OPCODES || 251 rhp->code < 1) 252 fprintf(stdout, " Code:%d id:%x [%d]", 253 rhp->code, rhp->id, ntohs(rhp->len)); 254 else 255 fprintf(stdout, " %s id:%x [%d]", 256 radius_codes[rhp->code].name, 257 rhp->id, ntohs(rhp->len)); 258 259 if(ntohs(rhp->len) > len) { 260 fputs(" [|radius]", stdout); 261 return; 262 } 263 264 l = len - RADFIXEDSZ; 265 if(!l) 266 return; 267 else 268 pp = data + RADFIXEDSZ; 269 270 first = 1; 271 while(l) { 272 if(!first) 273 fputc(',', stdout); 274 else 275 first = 0; 276 277 ac = *pp++; 278 al = *pp++; 279 280 if(al > l || al < 2) { 281 fputs(" [|radius]", stdout); 282 return; 283 } 284 285 al -= 2; 286 287 r_print_att(ac, al, pp); 288 289 pp += al; l -= al + 2; 290 } 291 } 292