1 /* $OpenBSD: radius_attr.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Internet Initiative Japan Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 33 #include <md5.h> 34 #include <stdbool.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 39 #include "radius.h" 40 41 #include "radius_local.h" 42 43 #define FIND_ATTRIBUTE_BEGIN(constness, redolabel) \ 44 constness RADIUS_ATTRIBUTE* attr; \ 45 constness RADIUS_ATTRIBUTE* end; \ 46 \ 47 attr = ATTRS_BEGIN(packet->pdata); \ 48 end = ATTRS_END(packet->pdata); \ 49 \ 50 for (;; ATTRS_ADVANCE(attr)) \ 51 { \ 52 redolabel \ 53 if (attr >= end) \ 54 break; \ 55 if (attr->type != type) \ 56 continue; \ 57 { 58 59 #define FIND_ATTRIBUTE_END \ 60 } } 61 62 #define FIND_VS_ATTRIBUTE_BEGIN(constness, redolabel) \ 63 constness RADIUS_ATTRIBUTE* attr; \ 64 constness RADIUS_ATTRIBUTE* end; \ 65 \ 66 attr = ATTRS_BEGIN(packet->pdata); \ 67 end = ATTRS_END(packet->pdata); \ 68 \ 69 for (;; ATTRS_ADVANCE(attr)) \ 70 { \ 71 redolabel \ 72 if (attr >= end) \ 73 break; \ 74 if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC) \ 75 continue; \ 76 if (attr->vendor != htonl(vendor)) \ 77 continue; \ 78 if (attr->vtype != vtype) \ 79 continue; \ 80 { 81 82 #define FIND_VS_ATTRIBUTE_END \ 83 } } 84 85 86 int 87 radius_get_raw_attr_ptr(const RADIUS_PACKET * packet, uint8_t type, 88 const void **ptr, size_t * length) 89 { 90 FIND_ATTRIBUTE_BEGIN(const,) { 91 *length = attr->length - 2; 92 *ptr = attr->data; 93 return (0); 94 } FIND_ATTRIBUTE_END; 95 96 return (-1); 97 } 98 99 int 100 radius_get_vs_raw_attr_ptr(const RADIUS_PACKET * packet, uint32_t vendor, 101 uint8_t vtype, const void **ptr, size_t * length) 102 { 103 FIND_VS_ATTRIBUTE_BEGIN(const,) { 104 *length = attr->vlength - 2; 105 *ptr = attr->vdata; 106 return (0); 107 } FIND_VS_ATTRIBUTE_END; 108 109 return (-1); 110 } 111 112 int 113 radius_get_raw_attr(const RADIUS_PACKET * packet, uint8_t type, void *buf, 114 size_t * length) 115 { 116 FIND_ATTRIBUTE_BEGIN(const,) { 117 *length = MINIMUM(attr->length - 2, *length); 118 memcpy(buf, attr->data, *length); 119 return (0); 120 } FIND_ATTRIBUTE_END; 121 122 return (-1); 123 } 124 125 int 126 radius_get_vs_raw_attr(const RADIUS_PACKET * packet, uint32_t vendor, 127 uint8_t vtype, void *buf, size_t * length) 128 { 129 FIND_VS_ATTRIBUTE_BEGIN(const,) { 130 *length = MINIMUM(attr->vlength - 2, *length); 131 memcpy(buf, attr->vdata, *length); 132 return (0); 133 } FIND_VS_ATTRIBUTE_END; 134 135 return (-1); 136 } 137 138 int 139 radius_get_raw_attr_cat(const RADIUS_PACKET * packet, uint8_t type, void *buf, 140 size_t * length) 141 { 142 size_t off = 0; 143 144 FIND_ATTRIBUTE_BEGIN(const,) { 145 if (buf != NULL) { 146 if (off + attr->length - 2 <= *length) 147 memcpy((char *)buf + off, attr->data, 148 attr->length - 2); 149 else 150 return (-1); 151 } 152 off += attr->length - 2; 153 } FIND_ATTRIBUTE_END; 154 155 *length = off; 156 157 return (0); 158 } 159 160 int 161 radius_get_vs_raw_attr_cat(const RADIUS_PACKET * packet, uint32_t vendor, 162 uint8_t vtype, void *buf, size_t * length) 163 { 164 size_t off = 0; 165 166 FIND_VS_ATTRIBUTE_BEGIN(const,) { 167 if (buf != NULL) { 168 if (off + attr->vlength - 2 <= *length) 169 memcpy((char *)buf + off, attr->vdata, 170 attr->vlength - 2); 171 else 172 return (-1); 173 } 174 off += attr->vlength - 2; 175 } FIND_VS_ATTRIBUTE_END; 176 177 *length = off; 178 179 return (0); 180 } 181 182 int 183 radius_put_raw_attr(RADIUS_PACKET * packet, uint8_t type, const void *buf, 184 size_t length) 185 { 186 RADIUS_ATTRIBUTE *newattr; 187 188 if (length > 255 - 2) 189 return (-1); 190 191 if (radius_ensure_add_capacity(packet, length + 2) != 0) 192 return (-1); 193 194 newattr = ATTRS_END(packet->pdata); 195 newattr->type = type; 196 newattr->length = length + 2; 197 memcpy(newattr->data, buf, length); 198 packet->pdata->length = htons(radius_get_length(packet) + length + 2); 199 200 return (0); 201 } 202 203 int 204 radius_put_vs_raw_attr(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype, 205 const void *buf, size_t length) 206 { 207 RADIUS_ATTRIBUTE *newattr; 208 209 if (length > 255 - 8) 210 return (-1); 211 if ((vendor & 0xff000000U) != 0) 212 return (-1); 213 214 if (radius_ensure_add_capacity(packet, length + 8) != 0) 215 return (-1); 216 217 newattr = ATTRS_END(packet->pdata); 218 newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC; 219 newattr->length = length + 8; 220 newattr->vendor = htonl(vendor); 221 newattr->vtype = vtype; 222 newattr->vlength = length + 2; 223 memcpy(newattr->vdata, buf, length); 224 packet->pdata->length = htons(radius_get_length(packet) + length + 8); 225 226 return (0); 227 } 228 229 int 230 radius_put_raw_attr_cat(RADIUS_PACKET * packet, uint8_t type, const void *buf, 231 size_t length) 232 { 233 int off, len0; 234 235 off = 0; 236 while (off < length) { 237 len0 = MINIMUM(length - off, 255 - 2); 238 239 if (radius_put_raw_attr(packet, type, (const char *)buf + off, 240 len0) != 0) 241 return (-1); 242 243 off += len0; 244 } 245 246 return (0); 247 } 248 249 int 250 radius_put_vs_raw_attr_cat(RADIUS_PACKET * packet, uint32_t vendor, 251 uint8_t vtype, const void *buf, size_t length) 252 { 253 int off, len0; 254 255 off = 0; 256 while (off < length) { 257 len0 = MINIMUM(length - off, 255 - 8); 258 259 if (radius_put_vs_raw_attr(packet, vendor, vtype, 260 (const char *)buf + off, len0) != 0) 261 return (-1); 262 263 off += len0; 264 } 265 266 return (0); 267 } 268 269 int 270 radius_set_raw_attr(RADIUS_PACKET * packet, 271 uint8_t type, const void *buf, size_t length) 272 { 273 FIND_ATTRIBUTE_BEGIN(,) { 274 if (length != attr->length - 2) 275 return (-1); 276 memcpy(attr->data, buf, length); 277 return (0); 278 } FIND_ATTRIBUTE_END; 279 280 return (-1); 281 } 282 283 int 284 radius_set_vs_raw_attr(RADIUS_PACKET * packet, 285 uint32_t vendor, uint8_t vtype, const void *buf, size_t length) 286 { 287 FIND_VS_ATTRIBUTE_BEGIN(,) { 288 if (length != attr->vlength - 2) 289 return (-1); 290 memcpy(attr->vdata, buf, length); 291 return (0); 292 } FIND_VS_ATTRIBUTE_END; 293 294 return (-1); 295 } 296 297 int 298 radius_del_attr_all(RADIUS_PACKET * packet, uint8_t type) 299 { 300 FIND_ATTRIBUTE_BEGIN(, redo:) { 301 RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr); 302 packet->pdata->length = 303 htons(ntohs(packet->pdata->length) - attr->length); 304 memmove(attr, next, ((char *)end) - ((char *)next)); 305 end = ATTRS_END(packet->pdata); 306 goto redo; 307 } FIND_ATTRIBUTE_END; 308 309 return (0); 310 } 311 312 int 313 radius_del_vs_attr_all(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype) 314 { 315 FIND_VS_ATTRIBUTE_BEGIN(, redo:) { 316 RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr); 317 packet->pdata->length = 318 htons(ntohs(packet->pdata->length) - attr->length); 319 memmove(attr, next, ((char *)end) - ((char *)next)); 320 end = ATTRS_END(packet->pdata); 321 goto redo; 322 } FIND_VS_ATTRIBUTE_END; 323 324 return (0); 325 } 326 327 bool 328 radius_has_attr(const RADIUS_PACKET * packet, uint8_t type) 329 { 330 FIND_ATTRIBUTE_BEGIN(const,) { 331 return (true); 332 } FIND_VS_ATTRIBUTE_END; 333 334 return (false); 335 } 336 337 bool 338 radius_has_vs_attr(const RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype) 339 { 340 FIND_VS_ATTRIBUTE_BEGIN(const,) { 341 return (true); 342 } FIND_VS_ATTRIBUTE_END; 343 344 return (false); 345 } 346 347 int 348 radius_get_string_attr(const RADIUS_PACKET * packet, uint8_t type, char *str, 349 size_t len) 350 { 351 const void *p; 352 size_t origlen; 353 354 if (radius_get_raw_attr_ptr(packet, type, &p, &origlen) != 0) 355 return (-1); 356 if (memchr(p, 0, origlen) != NULL) 357 return (-1); 358 if (len >= 1) { 359 len = MINIMUM(origlen, len - 1); 360 memcpy(str, (const char *)p, len); 361 str[len] = '\0'; 362 } 363 return (0); 364 } 365 366 int 367 radius_get_vs_string_attr(const RADIUS_PACKET * packet, 368 uint32_t vendor, uint8_t vtype, char *str, size_t len) 369 { 370 const void *p; 371 size_t origlen; 372 373 if (radius_get_vs_raw_attr_ptr(packet, 374 vendor, vtype, &p, &origlen) != 0) 375 return (-1); 376 if (memchr(p, 0, origlen) != NULL) 377 return (-1); 378 if (len >= 1) { 379 len = MINIMUM(origlen, len - 1); 380 memcpy(str, (const char *)p, len); 381 str[len] = '\0'; 382 } 383 384 return (0); 385 } 386 387 int 388 radius_put_string_attr(RADIUS_PACKET * packet, uint8_t type, const char *str) 389 { 390 return radius_put_raw_attr(packet, type, str, strlen(str)); 391 } 392 393 int 394 radius_put_vs_string_attr(RADIUS_PACKET * packet, 395 uint32_t vendor, uint8_t vtype, const char *str) 396 { 397 return radius_put_vs_raw_attr(packet, vendor, vtype, str, strlen(str)); 398 } 399 400 401 #define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ftname, tname, hton, ntoh) \ 402 int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet, \ 403 uint8_t type, tname *val) \ 404 { \ 405 const void *p; \ 406 tname nval; \ 407 size_t len; \ 408 \ 409 if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0) \ 410 return (-1); \ 411 if (len != sizeof(tname)) \ 412 return (-1); \ 413 memcpy(&nval, p, sizeof(tname)); \ 414 *val = ntoh(nval); \ 415 return (0); \ 416 } \ 417 \ 418 int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet, \ 419 uint32_t vendor, uint8_t vtype, tname *val) \ 420 { \ 421 const void *p; \ 422 tname nval; \ 423 size_t len; \ 424 \ 425 if (radius_get_vs_raw_attr_ptr(packet, \ 426 vendor, vtype, &p, &len) != 0) \ 427 return (-1); \ 428 if (len != sizeof(tname)) \ 429 return (-1); \ 430 memcpy(&nval, p, sizeof(tname)); \ 431 *val = ntoh(nval); \ 432 return (0); \ 433 } \ 434 \ 435 int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet, \ 436 uint8_t type, tname val) \ 437 { \ 438 tname nval; \ 439 \ 440 nval = hton(val); \ 441 return radius_put_raw_attr(packet, type, &nval, sizeof(tname)); \ 442 } \ 443 \ 444 int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet, \ 445 uint32_t vendor, uint8_t vtype, tname val) \ 446 { \ 447 tname nval; \ 448 \ 449 nval = hton(val); \ 450 return radius_put_vs_raw_attr(packet, vendor, vtype, \ 451 &nval, sizeof(tname)); \ 452 } \ 453 \ 454 int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet, \ 455 uint8_t type, tname val) \ 456 { \ 457 tname nval; \ 458 \ 459 nval = hton(val); \ 460 return radius_set_raw_attr(packet, type, &nval, sizeof(tname)); \ 461 } \ 462 \ 463 int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet, \ 464 uint32_t vendor, uint8_t vtype, tname val) \ 465 { \ 466 tname nval; \ 467 \ 468 nval = hton(val); \ 469 return radius_set_vs_raw_attr(packet, vendor, vtype, \ 470 &nval, sizeof(tname)); \ 471 } 472 473 #define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ftname, tname) \ 474 int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet, \ 475 uint8_t type, tname *val) \ 476 { \ 477 const void *p; \ 478 size_t len; \ 479 \ 480 if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0) \ 481 return (-1); \ 482 if (len != sizeof(tname)) \ 483 return (-1); \ 484 memcpy(val, p, sizeof(tname)); \ 485 return (0); \ 486 } \ 487 \ 488 int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet, \ 489 uint32_t vendor, uint8_t vtype, tname *val) \ 490 { \ 491 const void *p; \ 492 size_t len; \ 493 \ 494 if (radius_get_vs_raw_attr_ptr(packet, \ 495 vendor, vtype, &p, &len) != 0) \ 496 return (-1); \ 497 if (len != sizeof(tname)) \ 498 return (-1); \ 499 memcpy(val, p, sizeof(tname)); \ 500 return (0); \ 501 } \ 502 \ 503 int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet, \ 504 uint8_t type, const tname *val) \ 505 { \ 506 return radius_put_raw_attr(packet, type, val, sizeof(tname)); \ 507 } \ 508 \ 509 int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet, \ 510 uint32_t vendor, uint8_t vtype, const tname *val) \ 511 { \ 512 return radius_put_vs_raw_attr(packet, vendor, vtype, \ 513 val, sizeof(tname)); \ 514 } \ 515 \ 516 int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet, \ 517 uint8_t type, const tname *val) \ 518 { \ 519 return radius_set_raw_attr(packet, type, val, sizeof(tname)); \ 520 } \ 521 \ 522 int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet, \ 523 uint32_t vendor, uint8_t vtype, const tname *val) \ 524 { \ 525 return radius_set_vs_raw_attr(packet, vendor, vtype, \ 526 val, sizeof(tname)); \ 527 } 528 529 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint16, uint16_t, htons, ntohs) 530 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint32, uint32_t, htonl, ntohl) 531 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint64, uint64_t, htobe64, betoh64) 532 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ipv4, struct in_addr,,) 533 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ipv6, struct in6_addr) 534