1 /* $OpenBSD: print-radius.c,v 1.4 2000/10/03 14:21:56 ho Exp $ */ 2 3 #include <sys/types.h> 4 #include <netinet/in.h> 5 #include <arpa/inet.h> 6 7 #include <stdio.h> 8 #include <string.h> 9 10 /* RADIUS support for tcpdump, Thomas Ptacek <tqbf@enteract.com> */ 11 12 #include "interface.h" 13 #include "radius.h" 14 15 static void r_print_att(int code, int len, const u_char *val); 16 static void r_print_int(int code, int len, const u_char *val); 17 static void r_print_address(int code, int len, const u_char *val); 18 static void r_print_string(int code, int len, const u_char *val); 19 static void r_print_hex(int code, int len, const u_char *val); 20 21 /* --------------------------------------------------------------- */ 22 23 struct radius_ctable { 24 int code; 25 char *name; 26 }; 27 28 /* map opcodes to strings */ 29 30 #define DEFINED_OPCODES 11 31 32 static struct radius_ctable radius_codes[] = { 33 { -1, NULL }, 34 { RADIUS_CODE_ACCESS_REQUEST, "Axs?" }, 35 { RADIUS_CODE_ACCESS_ACCEPT, "Axs+" }, 36 { RADIUS_CODE_ACCESS_REJECT, "Axs-" }, 37 { RADIUS_CODE_ACCOUNT_REQUEST, "Act?" }, 38 { RADIUS_CODE_ACCOUNT_RESPONSE, "Act+" }, 39 { RADIUS_CODE_ACCOUNT_STATUS, "ActSt" }, 40 { RADIUS_CODE_PASSCHG_REQUEST, "Pchg?" }, 41 { RADIUS_CODE_PASSCHG_ACCEPT, "Pchg+" }, 42 { RADIUS_CODE_PASSCHG_REJECT, "Pchg-" }, 43 { RADIUS_CODE_ACCOUNT_MESSAGE, "ActMg" }, 44 { RADIUS_CODE_ACCESS_CHALLENGE, "Axs!" }, 45 { -1, NULL } 46 }; 47 48 /* --------------------------------------------------------------- */ 49 50 #define MAX_VALUES 20 51 52 struct radius_atable { 53 int code; 54 int encoding; 55 char *name; 56 char *values[MAX_VALUES]; 57 }; 58 59 /* map attributes to strings */ 60 61 /* the right way to do this is probably to read these values out 62 * of the actual RADIUS dictionary; this would require the machine 63 * running tcpdump to have that file installed, and it's not my 64 * program, so I'm not going to introduce new dependancies. Oh well. 65 */ 66 67 static struct radius_atable radius_atts[] = { 68 69 { RADIUS_ATT_USER_NAME, RD_STRING, "Name", { NULL } }, 70 { RADIUS_ATT_PASSWORD, RD_HEX, "Pass", { NULL } }, 71 { RADIUS_ATT_CHAP_PASS, RD_HEX, "CPass", { NULL } }, 72 { RADIUS_ATT_NAS_IP, RD_ADDRESS, "NAS-IP", { NULL } }, 73 { RADIUS_ATT_NAS_PORT, RD_INT, "NAS-Pt", { NULL } }, 74 75 { RADIUS_ATT_USER_SERVICE, RD_INT, "USvc", 76 { "", "Login", "Framed", "DB-Lgn", "DB-Frm", "Out", "Shell", NULL } }, 77 78 { RADIUS_ATT_PROTOCOL, RD_INT, "FProt", 79 { "", "PPP", "SLIP", NULL } }, 80 81 { RADIUS_ATT_FRAMED_ADDRESS, RD_ADDRESS, "F-IP", { NULL } }, 82 { RADIUS_ATT_NETMASK, RD_ADDRESS, "F-Msk", { NULL } }, 83 { RADIUS_ATT_ROUTING, RD_INT, "F-Rtg", { NULL } }, 84 { RADIUS_ATT_FILTER, RD_STRING, "FltID", { NULL } }, 85 { RADIUS_ATT_MTU, RD_INT, "F-MTU", { NULL } }, 86 { RADIUS_ATT_COMPRESSION, RD_INT, "F-Comp", { NULL } }, 87 { RADIUS_ATT_LOGIN_HOST, RD_ADDRESS, "L-Hst", { NULL } }, 88 89 { RADIUS_ATT_LOGIN_SERVICE, RD_INT, "L-Svc", 90 { "", "Telnt", "Rlog", "Clear", "PortM", NULL } }, 91 92 { RADIUS_ATT_LOGIN_TCP_PORT, RD_INT, "L-Pt", { NULL } }, 93 { RADIUS_ATT_OLD_PASSWORD, RD_HEX, "OPass", { NULL } }, 94 { RADIUS_ATT_PORT_MESSAGE, RD_STRING, "PMsg", { NULL } }, 95 { RADIUS_ATT_DIALBACK_NO, RD_STRING, "DB#", { NULL } }, 96 { RADIUS_ATT_DIALBACK_NAME, RD_STRING, "DBNm", { NULL } }, 97 { RADIUS_ATT_EXPIRATION, RD_DATE, "PExp", { NULL } }, 98 { RADIUS_ATT_FRAMED_ROUTE, RD_STRING, "F-Rt", { NULL } }, 99 { RADIUS_ATT_FRAMED_IPX, RD_ADDRESS, "F-IPX", { NULL } }, 100 { RADIUS_ATT_CHALLENGE_STATE, RD_STRING, "CState", { NULL } }, 101 { RADIUS_ATT_CLASS, RD_STRING, "Class", { NULL } }, 102 { RADIUS_ATT_VENDOR_SPECIFIC, RD_HEX, "Vendor", { NULL } }, 103 { RADIUS_ATT_SESSION_TIMEOUT, RD_INT, "S-TO", { NULL } }, 104 { RADIUS_ATT_IDLE_TIMEOUT, RD_INT, "I-TO", { NULL } }, 105 { RADIUS_ATT_TERMINATE_ACTION, RD_INT, "TermAct", { NULL } }, 106 { RADIUS_ATT_CALLED_ID, RD_STRING, "Callee", { NULL } }, 107 { RADIUS_ATT_CALLER_ID, RD_STRING, "Caller", { NULL } }, 108 109 { RADIUS_ATT_STATUS_TYPE, RD_INT, "Stat", 110 { "", "Start", "Stop", NULL } }, 111 112 { -1, -1, NULL, { NULL } } 113 114 }; 115 116 typedef void (*aselector)(int code, int len, const u_char *data); 117 aselector atselector[] = { 118 r_print_hex, 119 r_print_int, 120 r_print_int, 121 r_print_address, 122 r_print_string, 123 r_print_hex 124 }; 125 126 static void r_print_att(int code, int len, const u_char *data) { 127 struct radius_atable *atp; 128 int i; 129 130 for(atp = radius_atts; atp->code != -1; atp++) 131 if(atp->code == code) 132 break; 133 134 if(atp->code == -1) { 135 if(vflag > 1) { 136 fprintf(stdout, " %d =", code); 137 atselector[RD_HEX](code, len, data); 138 } else 139 fprintf(stdout, " %d", code); 140 141 return; 142 } 143 144 fprintf(stdout, " %s =", atp->name); 145 146 if(atp->encoding == RD_INT && *atp->values) { 147 int k = ntohl((*(int *)data)); 148 149 for(i = 0; atp->values[i] != NULL; i++) 150 /* SHOOT ME */ ; 151 152 if(k < i) { 153 fprintf(stdout, " %s", 154 atp->values[k]); 155 return; 156 } 157 } 158 159 atselector[atp->encoding](code, len, data); 160 } 161 162 static void r_print_int(int code, int len, const u_char *data) { 163 if(len < 4) { 164 fputs(" ?", stdout); 165 return; 166 } 167 168 fprintf(stdout, " %d", ntohl((*(int *)data))); 169 } 170 171 static void r_print_address(int code, int len, const u_char *data) { 172 if(len < 4) { 173 fputs(" ?", stdout); 174 return; 175 } 176 177 fprintf(stdout, " %s", inet_ntoa((*(struct in_addr *)data))); 178 } 179 180 static void r_print_string(int code, int len, const u_char *data) { 181 char string[128]; 182 183 if(!len) { 184 fputs(" ?", stdout); 185 return; 186 } 187 188 if(len > 127) 189 len = 127; 190 191 memset(string, 0, 128); 192 memcpy(string, data, len); 193 194 fprintf(stdout, " %s", string); 195 } 196 197 static void r_print_hex(int code, int len, const u_char *data) { 198 int i; 199 200 /* excuse me */ 201 202 fputs(" [", stdout); 203 204 for(i = 0; i < len; i++) 205 fprintf(stdout, "%x", data[i]); 206 207 fputc(']', stdout); 208 } 209 210 void radius_print(register const u_char *data, u_int len) { 211 const struct radius_header *rhp; 212 const u_char *pp; 213 int i, l, ac, al; 214 215 if(len < sizeof(struct radius_header)) { 216 fputs(" [|radius]", stdout); 217 return; 218 } 219 220 rhp = (struct radius_header *) data; 221 222 if(rhp->code > DEFINED_OPCODES || 223 rhp->code < 1) 224 fprintf(stdout, " Code:%d id:%x [%d]", 225 rhp->code, rhp->id, ntohs(rhp->len)); 226 else 227 fprintf(stdout, " %s id:%x [%d]", 228 radius_codes[rhp->code].name, 229 rhp->id, ntohs(rhp->len)); 230 231 if(ntohs(rhp->len) > len) { 232 fputs(" [|radius]", stdout); 233 return; 234 } 235 236 l = len - RADFIXEDSZ; 237 if(!l) 238 return; 239 else 240 pp = data + RADFIXEDSZ; 241 242 i = 0; /* XXX I don't see what 'i' is supposed to do here. */ 243 while(l) { 244 if(!i) fputc(',', stdout); i = 0; 245 246 ac = *pp++; 247 al = *pp++; 248 249 if(al > l || al < 2) { 250 fputs(" [|radius]", stdout); 251 return; 252 } 253 254 al -= 2; 255 256 r_print_att(ac, al, pp); 257 258 pp += al; l -= al + 2; 259 } 260 } 261