1 /* Copyright (c) 2019, SWITCH */
2 /* See LICENSE for licensing information. */
3
4 #include <ctype.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <regex.h>
8 #include <arpa/inet.h>
9 #include "debug.h"
10 #include "gconfig.h"
11 #include "hash.h"
12 #include "list.h"
13 #include "radmsg.h"
14 #include "rewrite.h"
15 #include "util.h"
16
17 static struct hash *rewriteconfs;
18
19 /** Extract attributes from string NAMEVAL, create a struct tlv and
20 * return the tlv. If VENDOR_FLAG, NAMEVAL is on the form
21 * "<vendor>:<name>:<val>" and otherwise it's "<name>:<val>". Return
22 * NULL if fields are missing or if conversion fails.
23 *
24 * FIXME: Should accept both names and numeric values, only numeric
25 * right now */
extractattr(char * nameval,char vendor_flag)26 struct tlv *extractattr(char *nameval, char vendor_flag) {
27 int len, name = 0;
28 int vendor = 0; /* Vendor 0 is reserved, see RFC 1700. */
29 uint32_t ival=0;
30 char *s, *s2;
31 struct tlv *a;
32
33 s = strchr(nameval, ':');
34 if (!s)
35 return NULL;
36 name = atoi(nameval);
37
38 if (vendor_flag) {
39 s2 = strchr(s + 1, ':');
40 if (!s2)
41 return NULL;
42 vendor = name;
43 name = atoi(s + 1);
44 s = s2;
45 }
46
47 s++;
48 if (isdigit(*s)) {
49 ival = atoi(s);
50 ival = htonl(ival);
51 len = 4;
52 s = (char *)&ival;
53 } else {
54 if (*s == '\'')
55 s++;
56
57 len = unhex(s,1);
58 if (len > 253)
59 return NULL;
60 }
61
62 if (name < 1 || name > 255)
63 return NULL;
64 a = malloc(sizeof(struct tlv));
65 if (!a)
66 return NULL;
67
68 a->v = (uint8_t *)stringcopy(s, len);
69 if (!a->v) {
70 free(a);
71 return NULL;
72 }
73 a->t = name;
74 a->l = len;
75
76 if (vendor_flag)
77 a = makevendortlv(vendor, a);
78
79 return a;
80 }
81
82 /* should accept both names and numeric values, only numeric right now */
extractmodattr(char * nameval)83 struct modattr *extractmodattr(char *nameval) {
84 int name = 0;
85 char *s, *t;
86 struct modattr *m;
87
88 if (!strncasecmp(nameval, "User-Name:/", 11)) {
89 s = nameval + 11;
90 name = 1;
91 } else {
92 s = strchr(nameval, ':');
93 name = atoi(nameval);
94 if (!s || name < 1 || name > 255 || s[1] != '/')
95 return NULL;
96 s += 2;
97 }
98 /* regexp, remove optional trailing / if present */
99 if (s[strlen(s) - 1] == '/')
100 s[strlen(s) - 1] = '\0';
101
102 for (t = strchr(s, '/'); t; t = strchr(t+1, '/'))
103 if (t == s || t[-1] != '\\')
104 break;
105 if (!t)
106 return NULL;
107 *t = '\0';
108 t++;
109
110 m = malloc(sizeof(struct modattr));
111 if (!m) {
112 debug(DBG_ERR, "malloc failed");
113 return NULL;
114 }
115 m->t = name;
116
117 m->replacement = stringcopy(t, 0);
118 if (!m->replacement) {
119 free(m);
120 debug(DBG_ERR, "malloc failed");
121 return NULL;
122 }
123
124 m->regex = malloc(sizeof(regex_t));
125 if (!m->regex) {
126 free(m->replacement);
127 free(m);
128 debug(DBG_ERR, "malloc failed");
129 return NULL;
130 }
131
132 if (regcomp(m->regex, s, REG_ICASE | REG_EXTENDED)) {
133 free(m->regex);
134 free(m->replacement);
135 free(m);
136 debug(DBG_ERR, "failed to compile regular expression %s", s);
137 return NULL;
138 }
139
140 return m;
141 }
142
extractmodvattr(char * nameval)143 struct modattr *extractmodvattr(char *nameval) {
144 uint32_t vendor;
145 char *s;
146 struct modattr *modvattr;
147
148 s = strchr(nameval, ':');
149 vendor = atoi(nameval);
150 if (!s || !vendor || !strchr(s+1,':'))
151 return NULL;
152 modvattr = extractmodattr(s+1);
153 if (modvattr)
154 modvattr ->vendor = vendor;
155 return modvattr;
156 }
157
addrewrite(char * value,uint8_t whitelist_mode,char ** rmattrs,char ** rmvattrs,char ** addattrs,char ** addvattrs,char ** modattrs,char ** modvattrs,char ** supattrs,char ** supvattrs)158 void addrewrite(char *value, uint8_t whitelist_mode, char **rmattrs, char **rmvattrs, char **addattrs,
159 char **addvattrs, char **modattrs, char **modvattrs, char **supattrs, char** supvattrs)
160 {
161 struct rewrite *rewrite = NULL;
162 int i, n;
163 uint8_t *rma = NULL;
164 uint32_t *p, *rmva = NULL;
165 struct list *adda = NULL, *moda = NULL, *modva = NULL, *supa = NULL;
166 struct tlv *a;
167 struct modattr *m;
168
169 if (rmattrs) {
170 for (n = 0; rmattrs[n]; n++);
171 rma = calloc(n + 1, sizeof(uint8_t));
172 if (!rma)
173 debugx(1, DBG_ERR, "malloc failed");
174
175 for (i = 0; i < n; i++)
176 if (!(rma[i] = attrname2val(rmattrs[i])))
177 debugx(1, DBG_ERR, "addrewrite: removing invalid attribute %s", rmattrs[i]);
178 freegconfmstr(rmattrs);
179 rma[i] = 0;
180 }
181
182 if (rmvattrs) {
183 for (n = 0; rmvattrs[n]; n++);
184 rmva = calloc(2 * n + 1, sizeof(uint32_t));
185 if (!rmva)
186 debugx(1, DBG_ERR, "malloc failed");
187
188 for (p = rmva, i = 0; i < n; i++, p += 2)
189 if (!vattrname2val(rmvattrs[i], p, p + 1))
190 debugx(1, DBG_ERR, "addrewrite: removing invalid vendor attribute %s", rmvattrs[i]);
191 freegconfmstr(rmvattrs);
192 *p = 0;
193 }
194
195 if (addattrs) {
196 adda = list_create();
197 if (!adda)
198 debugx(1, DBG_ERR, "malloc failed");
199 for (i = 0; addattrs[i]; i++) {
200 a = extractattr(addattrs[i], 0);
201 if (!a)
202 debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", addattrs[i]);
203 if (!list_push(adda, a))
204 debugx(1, DBG_ERR, "malloc failed");
205 }
206 freegconfmstr(addattrs);
207 }
208
209 if (addvattrs) {
210 if (!adda)
211 adda = list_create();
212 if (!adda)
213 debugx(1, DBG_ERR, "malloc failed");
214 for (i = 0; addvattrs[i]; i++) {
215 a = extractattr(addvattrs[i], 1);
216 if (!a)
217 debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", addvattrs[i]);
218 if (!list_push(adda, a))
219 debugx(1, DBG_ERR, "malloc failed");
220 }
221 freegconfmstr(addvattrs);
222 }
223
224 if (modattrs) {
225 moda = list_create();
226 if (!moda)
227 debugx(1, DBG_ERR, "malloc failed");
228 for (i = 0; modattrs[i]; i++) {
229 m = extractmodattr(modattrs[i]);
230 if (!m)
231 debugx(1, DBG_ERR, "addrewrite: modifying invalid attribute %s", modattrs[i]);
232 if (!list_push(moda, m))
233 debugx(1, DBG_ERR, "malloc failed");
234 }
235 freegconfmstr(modattrs);
236 }
237
238 if (modvattrs) {
239 modva = list_create();
240 if (!modva)
241 debugx(1, DBG_ERR, "malloc failed");
242 for (i = 0; modvattrs[i]; i++) {
243 m = extractmodvattr(modvattrs[i]);
244 if (!m)
245 debugx(1, DBG_ERR, "addrewrite: modifying invalid vendor attribute %s", modvattrs[i]);
246 if (!list_push(modva, m))
247 debugx(1, DBG_ERR, "malloc failed");
248 }
249 freegconfmstr(modvattrs);
250 }
251
252 if (supattrs) {
253 supa = list_create();
254 if (!supa)
255 debugx(1, DBG_ERR, "malloc failed");
256 for (i = 0; supattrs[i]; i++) {
257 a = extractattr(supattrs[i], 0);
258 if (!a)
259 debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", supattrs[i]);
260 if (!list_push(supa, a))
261 debugx(1, DBG_ERR, "malloc failed");
262 }
263 freegconfmstr(supattrs);
264 }
265
266 if (supvattrs) {
267 if (!supa)
268 supa = list_create();
269 if (!supa)
270 debugx(1, DBG_ERR, "malloc failed");
271 for (i = 0; supvattrs[i]; i++) {
272 a = extractattr(supvattrs[i], 1);
273 if (!a)
274 debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", supvattrs[i]);
275 if (!list_push(supa, a))
276 debugx(1, DBG_ERR, "malloc failed");
277 }
278 freegconfmstr(supvattrs);
279 }
280
281 if (rma || rmva || adda || moda || modva || supa) {
282 rewrite = malloc(sizeof(struct rewrite));
283 if (!rewrite)
284 debugx(1, DBG_ERR, "malloc failed");
285 rewrite->whitelist_mode = whitelist_mode;
286 rewrite->removeattrs = rma;
287 rewrite->removevendorattrs = rmva;
288 rewrite->addattrs = adda;
289 rewrite->modattrs = moda;
290 rewrite->modvattrs = modva;
291 rewrite->supattrs = supa;
292 }
293
294 if (!rewriteconfs)
295 rewriteconfs = hash_create();
296 if (!hash_insert(rewriteconfs, value, strlen(value), rewrite))
297 debugx(1, DBG_ERR, "malloc failed");
298 debug(DBG_DBG, "addrewrite: added rewrite block %s", value);
299 }
300
getrewrite(char * alt1,char * alt2)301 struct rewrite *getrewrite(char *alt1, char *alt2) {
302 struct rewrite *r;
303
304 if (alt1)
305 if ((r = hash_read(rewriteconfs, alt1, strlen(alt1))))
306 return r;
307 if (alt2)
308 if ((r = hash_read(rewriteconfs, alt2, strlen(alt2))))
309 return r;
310 return NULL;
311 }
312
findvendorsubattr(uint32_t * attrs,uint32_t vendor,uint32_t subattr)313 int findvendorsubattr(uint32_t *attrs, uint32_t vendor, uint32_t subattr) {
314 if (!attrs)
315 return 0;
316
317 for (; attrs[0]; attrs += 2)
318 if (attrs[0] == vendor && attrs[1] == subattr)
319 return 1;
320 return 0;
321 }
322
323 /* returns 1 if entire element is to be removed, else 0 */
dovendorrewriterm(struct tlv * attr,uint32_t * removevendorattrs,int inverted)324 int dovendorrewriterm(struct tlv *attr, uint32_t *removevendorattrs, int inverted) {
325 uint8_t alen, sublen;
326 uint32_t vendor;
327 uint8_t *subattrs;
328
329 if (!removevendorattrs || attr->l <= 4)
330 return 0;
331
332 memcpy(&vendor, attr->v, 4);
333 vendor = ntohl(vendor);
334 while (*removevendorattrs && *removevendorattrs != vendor)
335 removevendorattrs += 2;
336 if (!*removevendorattrs)
337 return 0;
338
339 if (findvendorsubattr(removevendorattrs, vendor, 256))
340 return 1; /* remove entire vendor attribute */
341
342 sublen = attr->l - 4;
343 subattrs = attr->v + 4;
344
345 if (!attrvalidate(subattrs, sublen)) {
346 debug(DBG_INFO, "dovendorrewrite: vendor attribute validation failed, no rewrite");
347 return 0;
348 }
349
350 while (sublen > 1) {
351 alen = ATTRLEN(subattrs);
352 sublen -= alen;
353 if (!!findvendorsubattr(removevendorattrs, vendor, ATTRTYPE(subattrs)) != !!inverted) {
354 memmove(subattrs, subattrs + alen, sublen);
355 attr->l -= alen;
356 } else
357 subattrs += alen;
358 }
359 if ((attr->l <= 4) != !!inverted)
360 return 1;
361 return 0;
362 }
363
364 /*if inverted is true, remove all attributes except those listed */
dorewriterm(struct radmsg * msg,uint8_t * rmattrs,uint32_t * rmvattrs,int inverted)365 void dorewriterm(struct radmsg *msg, uint8_t *rmattrs, uint32_t *rmvattrs, int inverted) {
366 struct list_node *n, *p;
367 struct tlv *attr;
368
369 p = NULL;
370 n = list_first(msg->attrs);
371 while (n) {
372 attr = (struct tlv *)n->data;
373 if (((rmattrs && strchr((char *)rmattrs, attr->t)) ||
374 (rmvattrs && attr->t == RAD_Attr_Vendor_Specific && dovendorrewriterm(attr, rmvattrs, inverted))) != !!inverted) {
375 list_removedata(msg->attrs, attr);
376 freetlv(attr);
377 n = p ? list_next(p) : list_first(msg->attrs);
378 } else {
379 p = n;
380 n = list_next(n);
381 }
382 }
383 }
384
dorewritemodattr(struct tlv * attr,struct modattr * modattr)385 int dorewritemodattr(struct tlv *attr, struct modattr *modattr) {
386 size_t nmatch = 10, reslen = 0, start = 0;
387 regmatch_t pmatch[10], *pfield;
388 int i;
389 char *in, *out;
390
391 in = stringcopy((char *)attr->v, attr->l);
392 if (!in)
393 return 0;
394
395 if (regexec(modattr->regex, in, nmatch, pmatch, 0)) {
396 free(in);
397 return 1;
398 }
399
400 out = modattr->replacement;
401
402 for (i = start; out[i]; i++) {
403 if (out[i] == '\\' && out[i + 1] >= '1' && out[i + 1] <= '9') {
404 pfield = &pmatch[out[i + 1] - '0'];
405 if (pfield->rm_so >= 0) {
406 reslen += i - start + pfield->rm_eo - pfield->rm_so;
407 start = i + 2;
408 }
409 i++;
410 }
411 }
412 reslen += i - start;
413 if (!resizeattr(attr, reslen)) {
414 debug(DBG_INFO, "rewritten attribute to length %d failed, discarding message", reslen);
415 free(in);
416 return 0;
417 }
418
419 start = 0;
420 reslen = 0;
421 for (i = start; out[i]; i++) {
422 if (out[i] == '\\' && out[i + 1] >= '1' && out[i + 1] <= '9') {
423 pfield = &pmatch[out[i + 1] - '0'];
424 if (pfield->rm_so >= 0) {
425 memcpy(attr->v + reslen, out + start, i - start);
426 reslen += i - start;
427 memcpy(attr->v + reslen, in + pfield->rm_so, pfield->rm_eo - pfield->rm_so);
428 reslen += pfield->rm_eo - pfield->rm_so;
429 start = i + 2;
430 }
431 i++;
432 }
433 }
434 free(in);
435
436 memcpy(attr->v + reslen, out + start, i - start);
437 return 1;
438 }
439
replacesubtlv(struct tlv * vendortlv,uint8_t * p,struct tlv * newtlv)440 int replacesubtlv(struct tlv *vendortlv, uint8_t *p, struct tlv *newtlv) {
441 int size_diff;
442 uint8_t rem_size, *next_attr;
443
444 size_diff = newtlv->l - ATTRLEN(p);
445 next_attr = p+ATTRLEN(p);
446 rem_size = (vendortlv->v + vendortlv->l) - next_attr;
447
448 if (size_diff < 0)
449 memmove(next_attr + size_diff, next_attr, rem_size);
450 if (!resizeattr(vendortlv, vendortlv->l+size_diff))
451 return 0;
452 if (size_diff > 0)
453 memmove(next_attr + size_diff, next_attr, rem_size);
454
455 tlv2buf(p, newtlv);
456 return 1;
457 }
458
dorewritemodvattr(struct tlv * vendortlv,struct modattr * modvattr)459 int dorewritemodvattr(struct tlv *vendortlv, struct modattr *modvattr) {
460 struct tlv *tmpattr;
461 int offset;
462
463 if (vendortlv->l <= 4 || !attrvalidate(vendortlv->v+4, vendortlv->l-4))
464 return 0;
465 for (offset = 4; offset < vendortlv->l; offset += ATTRLEN(vendortlv->v+offset)) {
466 if (ATTRTYPE(vendortlv->v+offset) == modvattr->t) {
467 tmpattr = maketlv(ATTRTYPE(vendortlv->v+offset), ATTRVALLEN(vendortlv->v+offset), ATTRVAL(vendortlv->v+offset));
468 if (!tmpattr)
469 return 0;
470 if (dorewritemodattr(tmpattr, modvattr)) {
471 int size_diff = tmpattr->l - ATTRVALLEN(vendortlv->v+offset);
472 int rem_size = vendortlv->l - offset - ATTRLEN(vendortlv->v+offset);
473 uint8_t *next;
474
475 if (size_diff > 0)
476 if (!resizeattr(vendortlv, vendortlv->l+size_diff)) {
477 freetlv(tmpattr);
478 return 0;
479 }
480 next = vendortlv->v + offset + ATTRLEN(vendortlv->v+offset);
481 memmove(next + size_diff, next, rem_size);
482 if (size_diff < 0)
483 if (!resizeattr(vendortlv, vendortlv->l+size_diff)) {
484 freetlv(tmpattr);
485 return 0;
486 }
487
488 tlv2buf(vendortlv->v+offset, tmpattr);
489 } else {
490 freetlv(tmpattr);
491 return 0;
492 }
493 freetlv(tmpattr);
494 }
495 }
496 return 1;
497 }
498
dorewritemod(struct radmsg * msg,struct list * modattrs,struct list * modvattrs)499 int dorewritemod(struct radmsg *msg, struct list *modattrs, struct list *modvattrs) {
500 struct list_node *n, *m;
501 uint32_t vendor;
502
503 for (n = list_first(msg->attrs); n; n = list_next(n)) {
504 struct tlv *attr = (struct tlv *)n->data;
505 if (attr->t == RAD_Attr_Vendor_Specific) {
506 memcpy(&vendor, attr->v, 4);
507 vendor = ntohl(vendor);
508 for (m = list_first(modvattrs); m; m = list_next(m)) {
509 if (vendor == ((struct modattr *)m->data)->vendor &&
510 !dorewritemodvattr(attr, (struct modattr*)m->data))
511 return 0;
512 }
513 } else {
514 for (m = list_first(modattrs); m; m = list_next(m))
515 if (((struct tlv *)n->data)->t == ((struct modattr *)m->data)->t &&
516 !dorewritemodattr((struct tlv *)n->data, (struct modattr *)m->data))
517 return 0;
518 }
519 }
520 return 1;
521 }
522
dorewriteadd(struct radmsg * msg,struct list * addattrs)523 int dorewriteadd(struct radmsg *msg, struct list *addattrs) {
524 struct list_node *n;
525 struct tlv *a;
526
527 for (n = list_first(addattrs); n; n = list_next(n)) {
528 a = copytlv((struct tlv *)n->data);
529 if (!a)
530 return 0;
531 if (!radmsg_add(msg, a)) {
532 freetlv(a);
533 return 0;
534 }
535 }
536 return 1;
537 }
538
dorewritesup(struct radmsg * msg,struct list * supattrs)539 int dorewritesup(struct radmsg *msg, struct list *supattrs) {
540 struct list_node *n, *p;
541 struct tlv *attr, *supattr;
542 uint8_t exist, *vendortype, *v;;
543
544 for (n = list_first(supattrs); n; n = list_next(n)) {
545 supattr = (struct tlv *)n->data;
546 exist = 0;
547 for(p = list_first(msg->attrs); p; p = list_next(p)) {
548 attr = (struct tlv *)p->data;
549 if (attr->t == supattr->t && attr->t != RAD_Attr_Vendor_Specific) {
550 exist = 1;
551 break;
552 } else if (supattr->t == RAD_Attr_Vendor_Specific && attr->t == RAD_Attr_Vendor_Specific &&
553 memcmp (supattr->v, attr->v, 4)==0) {
554 if (!attrvalidate(attr->v+4, attr->l-4)) {
555 debug(DBG_INFO, "dorewritesup: vendor attribute validation failed, no rewrite");
556 return 0;
557 }
558 vendortype = (uint8_t *)supattr->v+4;
559 for (v=attr->v+4; v < attr->v + attr->l; v += *(v+1)){
560 if (*v == *vendortype) {
561 exist = 1;
562 break;
563 }
564 }
565 if (exist) break;
566 }
567 }
568 if (!exist) {
569 supattr = copytlv(supattr);
570 if (!supattr)
571 return 0;
572 if (!radmsg_add(msg, supattr)) {
573 freetlv(supattr);
574 return 0;
575 }
576 }
577 }
578 return 1;
579 }
580
dorewrite(struct radmsg * msg,struct rewrite * rewrite)581 int dorewrite(struct radmsg *msg, struct rewrite *rewrite) {
582 int rv = 1; /* Success. */
583
584 if (rewrite) {
585 if (rewrite->removeattrs || rewrite->removevendorattrs)
586 dorewriterm(msg, rewrite->removeattrs, rewrite->removevendorattrs, rewrite->whitelist_mode);
587 if (rewrite->modattrs || rewrite->modvattrs)
588 if (!dorewritemod(msg, rewrite->modattrs, rewrite->modvattrs))
589 rv = 0;
590 if (rewrite->supattrs)
591 if (!dorewritesup(msg, rewrite->supattrs))
592 rv = 0;
593 if (rewrite->addattrs)
594 if (!dorewriteadd(msg, rewrite->addattrs))
595 rv = 0;
596 }
597 return rv;
598 }
599
600 /** Ad vendor attribute with VENDOR + ATTR and push it on MSG. ATTR
601 * is consumed. */
addvendorattr(struct radmsg * msg,uint32_t vendor,struct tlv * attr)602 int addvendorattr(struct radmsg *msg, uint32_t vendor, struct tlv *attr) {
603 struct tlv *vattr;
604
605 vattr = makevendortlv(vendor, attr);
606 if (!vattr) {
607 freetlv(attr);
608 return 0;
609 }
610 if (!radmsg_add(msg, vattr)) {
611 freetlv(vattr);
612 return 0;
613 }
614 return 1;
615 }
616
617 /* Local Variables: */
618 /* c-file-style: "stroustrup" */
619 /* End: */
620